题目描述:
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"
.
自己写的一个算法超时了:
public class Solution {
public boolean wordBreak(String s, Set<String> wordDict) {
int n=s.length();
boolean[][] dp=new boolean[n][n];
for(int l=1;l<=n;l++){
for(int i=0;i<n-l+1;i++){
loop:for(int j=i;j<i+l;j++){
if(wordDict.contains(s.substring(i, j+1)))
dp[i][j]=true;
else{
for(int k=i;k<j;k++){
if(dp[i][k]&&dp[k+1][j]){
dp[i][j]=true;
continue loop;
}
}
dp[i][j]=false;
}
}
}
}
return dp[0][n-1];
}
}
正确的AC算法如下:
自上而下的备忘录法:
public class Solution {
private HashMap<String, Boolean> map = new HashMap<>();
public boolean wordBreak(String s, Set<String> wordDict) {
if (s.length() == 0) return true;
if (map.containsKey(s)) return map.get(s);
for (int i = 0; i <= s.length(); i++) {
String prefix = s.substring(0, i);
if (wordDict.contains(prefix)) {
if (wordBreak(s.substring(i), wordDict)) {
map.put(s, true);
return true;
}
}
}
map.put(s, false);
return false;
}
}
这个算法还可以优化:
记下来dict中单词的最大长度,这样就不用查询每一个单词都从头查到尾了。
上面是用的map来记录,这里一个set和一个数组来代替。
public class Solution {
public boolean wordBreak(String s, Set<String> wordDict) {
if (s == null || s.length() == 0) {
return false;
}
int maxLength = maxLengthStr(wordDict);
return dfs(s, 0, wordDict, new boolean[s.length()], maxLength);
}
private boolean dfs(String s, int idx, Set<String> wordDict, boolean[] unbreakable, int maxLength) {
if (idx >= s.length()) {
return true;
} else if (unbreakable[idx]) {
return false;
} else {
int end = Math.min(idx + maxLength, s.length());
for (int i = idx + 1; i <= end; i++) {
if (wordDict.contains(s.substring(idx, i))) {
if (dfs(s, i, wordDict, unbreakable, maxLength)) {
return true;
}
}
}
unbreakable[idx] = true;
return false;
}
}
private int maxLengthStr(Set<String> wordDict) {
int max = 0;
for (String str : wordDict) {
max = Math.max(max, str.length());
}
return max;
}
}
自下而上的dp:
public class Solution {
public boolean wordBreak(String s, Set<String> wordDict) {
if (s == null || s.isEmpty()) {
return false;
}
int n = s.length();
boolean[] breakable = new boolean[n + 1];
breakable[0] = true;
for (int i = 1; i <= n; i++) {
for (int j = i - 1; j >= 0; j--) {
if (breakable[j] && wordDict.contains(s.substring(j, i))) {
breakable[i] = true;
break;
}
}
}
return breakable[n];
}
}