面试题 17.13. 恢复空格
题目链接
题目分析
这个题是非常明显的区间DP问题,我们使用两个for循环就可以解决问题。第一重for循环用于定位sentence中每个字符的位置,第二重循环用于定位其长度。
但是在做的时候,我第二轮循环是从1开始一直找到当前字符的位置,这样会导致超时问题,只通过了65个测试用例,需要进一步的优化。
留意到超时的情况,主要是由于我们在寻找长度的切割了很多不必要的字串出来,例如
- 切割出来的字符串在字典中根本没这个字符串的长度
同时我们还要借助list来进行查找,我们要知道arraylist默认查找是O(n)的时间复杂度,这里也会带来很大的开销。
于是我进行了进一步的优化,我们第二重for循环用于遍历字典中的所有字符串,如果字典中的字符串长度小于等于当前字符的位置并且切下来的字串和字典中的字符串相等,我们就进行dp数组的更新。最终该算法击败了55%的人。
代码实现
public int respace(String[] dictionary, String sentence){
//这个方法会在第65个测试用例中超时,因为我们的第二重循环出现了大量的不必要计算。我改成了第二种方法。
/* int[] dp = new int[sentence.length() + 1];
List<String> list = Arrays.asList(dictionary);
//当前访问的下标+1
for(int i = 1; i < sentence.length()+1; i++){
//当前截取的字符串长度
dp[i] = dp[i-1];
for(int j = 1; j <= i; j++){
if(list.contains(sentence.substring(i-j,i))){
dp[i] = Math.max(dp[i-j] + j,dp[i]);
}
}
}
return sentence.length() - dp[dp.length-1];*/
int[] dp = new int[sentence.length() + 1];
//当前访问的下标+1
for(int i = 1; i < sentence.length()+1; i++){
//当前截取的字符串长度
dp[i] = dp[i-1];
for(String str : dictionary){
int length = str.length();
if(length <= i && str.equals(sentence.substring(i - length, i))){
dp[i] = Math.max(dp[i - length] + length, dp[i]);
}
}
}
return sentence.length() - dp[dp.length-1];
}
总结
DP问题还是很多可优化空间的