您的位置:首页 > 其它

139. Word Break

2016-12-01 23:13 295 查看
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

For example, given
s = 
"leetcode"
,
dict = 
["leet", "code"]
.

Return true because 
"leetcode"
 can be segmented as 
"leet
code"
.

这是以前刷题写的博客,尼玛刷完就忘了,当时一心想着刷题的数量,到现在就TMD感觉什么都没刷一样,看来刷题应有的姿势是:刷题自是手段,刷的过程中学习别人怎么思考的才是王道,不扯了,总结

第一反应就是递归,很快写出

import java.util.List;

public class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
if("".equals(s)) return true;

for(String t : wordDict) {
if(s.startsWith(t) && wordBreak(s.substring(t.length()), wordDict))
return true;
}

return false;
}
}

TLE没商量,那就用Hash memorize吧

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class recrusion {

Set<String> canBreak = new HashSet<String>();

public boolean wordBreak(String s, List<String> wordDict) {

4000
if("".equals(s) || canBreak.contains(s)) return true;

for(String t : wordDict) {
if(s.startsWith(t) && wordBreak(s.substring(t.length()), wordDict)) {
canBreak.add(s);
return true;
}
}

return false;
}
}

还是TLE,考虑到已经有递归和优化的形式了,为什么不用DP呢?但是这个TMD的递归好像不能划分子问题,即使知道了dp[i]之前的值,好像跟求解dp[i]并没有什么关系,自此就卡主了。‘

那就在Discuss里面看答案吧,我差,有DFS,BFS,DP,为毛老子不行

然后发现:在DFS的时候每一步决策他们看的是String s的index,而不是在dict里面选择一个就继续进行下一步,好,那我改

public class recrusion2 {

Set<String> canBreak = new HashSet<String>();

public boolean wordBreak(String s, List<String> wordDict) {
return dfs(s, 0, wordDict);
}

private boolean dfs(String s, int start, List<String> wordDict) {
if(start == s.length() || canBreak.contains(s.substring(start))) return true;

for(int i=start; i<s.length(); i++) {
if(wordDict.contains(s.substring(start, i+1)) && dfs(s, i+1, wordDict)) {
canBreak.add(s);
return true;
}
}

return false;
}
}

继续TLE,仔细看,发现canBreak这个set根本就没有起到作用,因为他是在return true的时候才会有String被加到里面,这是已经可以确定答案就是true,TMD的还要加个蛋啊

那就弄个cannotBreak的set吧

public class recursion4 {

Set<String> cannotBreak = new HashSet<String>();

public boolean wordBreak(String s, List<String> wordDict) {
return dfs(s, 0, wordDict);
}

private boolean dfs(String s, int start, List<String> wordDict) {
if(start == s.length()) return true;
if(cannotBreak.contains(s.substring(start))) return false;

for(int i=start; i<s.length(); i++) {
if(wordDict.contains(s.substring(start, i+1))) {
if(dfs(s, i+1, wordDict))
return true;
else
cannotBreak.add(s.substring(i+1));
}
}

return false;
}
}

终于AC,划分子结构也挺明了的了,按照递归的反方向DP就OK

import java.util.List;

public class Solution {

public boolean wordBreak(String s, List<String> wordDict) {
boolean[] dp = new boolean[s.length()+1];
dp[s.length()] = true;

for(int i=s.length()-1; i>=0; i--)
for(int j=i+1; j<=s.length(); j++) {
if(dp[j] && wordDict.contains(s.substring(i, j))) {
dp[i] = true;
break;
}
}

return dp[0];
}
}

PS:

(1)递归用set memorize的时候可以memorize index

(2)递归+Memorize 复杂度O(N^2),因为index 需要遍历一遍,判断从0 到index i可不可行需要i次查找Set,而index不会减小,一旦遍历到index i,index 之前的直接在Set里面拿
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: