这个题解法很多,顺便理一下思路
DP几步走:
1. 写状态转移方程,根据方程就可以得到基本DP方法,注意时间复杂度和空间复杂度的计算。
2.很多DP划分方式很多,所以注意使用记忆搜索来优化DP的处理速度。
3. 事实上使用DP递归调用仍然使用了大量的存储空间,使用DP自底向上可以实现O(1)存储的实现,但往往那个稍显困难。
Word Break这题接法很多,最笨的接法是直接DP,
解法1: 直接DP.
既然要把一个String s转化为多个单词的组合,可以从头向尾匹配一个一个字符匹配,即(参考WordBreakS2)
solve(int start){
for(int i=start;i>=s.length ();i++){
String tmp=st.substring(start,i);
if(sset.contains(tmp)){
solve(i);
}
}
}
但这有问题,dict里面出现a,aa,aaa,aaaa绝对超时,因为会重复查找,因此为了避免重复计算,最常用的方法就是记忆搜索。用数组存储中间结果。
解法2:记忆搜索+DP res存结果 0为没存结果,-1为false,1为正确,其实1不用存。
320ms过大集合
Set<String> sset;
String st;
int[] res;
private boolean dp1(int start){
if(res[start]!=0){
if(res[start]>0)
return true;
else
return false;
}
boolean success=false;
for(int i=st.length();i>=start+1;i--){
String tmp=st.substring(start,i);
//System.out.println("tmp=["+start+","+i+"]"+tmp);
if(sset.contains(tmp)){
if(i==st.length()){
res[start]=1;
return true;
}
else
success=dp1(i);
}
if(success){
res[start]=1;
return true;
}
}
res[start]=-1;
return false;
}
public boolean wordBreak(String s, Set<String> ss) {
sset=ss;
st=s;
res=new int[s.length()+10];
return dp1(0);
}
这就是我的能力极限了,最近看到很多大牛谈到bottom up的DP,很是神往,参考了一些资料。
http://sobuhu.com/algorithm/2012/12/19/dynamic-programming-1.html
http://pisces.ck.tp.edu.tw/~peng/index.php?action=showfile&file=ffea8e9bf9695ed5ccc35eb71d3b2ac6175cab78a
顺便比较一下神写的代码和渣写的代码
public class Solution {
public boolean wordBreak(String s, Set<String> dict) {
return wordBreakHelper(s, dict, 0);
}
public boolean wordBreakHelper(String s, Set<String> dict, int start){
if(start == s.length())
return true;
for(String a: dict){
int len = a.length();
int end = start+len;
//end index should be <= string length
if(end > s.length())
continue;
if(s.substring(start, start+len).equals(a))
if(wordBreakHelper(s, dict, start+len))
return true;
}
return false;
}
}
解法3:神代码 似乎还是记忆搜索
public class Solution {
public boolean wordBreak(String s, Set<String> dict) {
boolean[] t = new boolean[s.length()+1];
t[0] = true; //set first to be true, why?
//Because we need initial state
for(int i=0; i<s.length(); i++){
//should continue from match position
if(!t[i])
continue;
for(String a: dict){
int len = a.length();
int end = i + len;
if(end > s.length())
continue;
if(s.substring(i, end).equals(a)){
t[end] = true;
}
}
}
return t[s.length()];
}
}
这个方法实际还是dp的记忆搜索,从头节点开始遍历,能走到的点标记true,看看尾节点能不能标记true。一定要注意,处理这种单词类型的时候一定要想好遍历的基本单位是什么,到底是一个一个字符走,还是一个一个单词走。想清楚,才能走的更快