先上自己的代码
1 class Solution { 2 public: 3 bool wordBreak(string s, unordered_set<string> &dict) { 4 vector<bool> dp(s.size()+1,false);//dp[i]表示从下标0开始的长度为i的子串能否满足word break; 5 dp[0] = true;//相当于分割成了空串和完整的字符串s。不能让dp[0]成为&&判断的绊脚石(&&右边如果是个完整串且为真,不能让dp[0]给破坏了) 6 for (int i = 1; i <= int(s.size()); i++)//i表示当前串的长度(DP自底向上,串的长度从1到n依次增大、记录数据。) 7 { 8 for (int k = 0; k < i; k++)//k的意义为将当前长度为i的大串分成左边长为k,右边长为i-k的两个字串。 9 //随着k的不同,将长为i的串以不同的左右比例依次切分看能否word break. 10 { 11 if (dp[k] && dict.find(s.substr(k, i - k))!=dict.end())//下标不要搞错!substr第一个参数是k不是k+1。 12 { 13 dp[i] = true; 14 break; 15 } 16 } 17 } 18 return dp[s.size()]; 19 } 20 };
======================================================================================================================
http://www.cnblogs.com/lautsie/p/3371354.html
LeetCode越来越大姨妈了,Submit上去又卡住了,先假设通过了吧。这道题拿到思考先是递归,然后有重复子状态,显然是DP。用f(i,j)表示字符串S从i到j的子串是否可分割,则有:f(0,n) = f(0,i) && f(i,n)。
但是如果自底向上求的话会计算很多不需要的,比如leet已经在字典里了,很多情况下就不需要计算下面的l,e,e,t了,所以自顶向下递归+备忘录会是更快的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
import
java.util.*;
public
class
Solution {
private
int
f[][] =
null
;
public
boolean
wordBreak(String s, Set<String> dict) {
int
len = s.length();
f =
new
int
[len][len];
// 0 for unvisited, -1 for false, 1 for true
return
wordBreak(s, dict,
0
, len-
1
);
}
private
boolean
wordBreak(String s, Set<String> dict,
int
i,
int
j) {
if
(f[i][j] ==
1
)
return
true
;
if
(f[i][j] == -
1
)
return
false
;
String s0 = s.substring(i, j +
1
);
if
(dict.contains(s0)) {
f[i][j] =
1
;
return
true
;
}
for
(
int
k = i +
1
; k <= j; k++) {
if
(wordBreak(s, dict, i, k-
1
) && wordBreak(s, dict, k, j)) {
f[i][j] =
1
;
return
true
;
}
}
f[i][j] = -
1
;
return
false
;
}
}
|
但是如果自底向上,状态就可以滚动数组优化少一维表示,比如下面,用wordB[i]表示从0开始长度为i的子串是否能分割。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class
Solution {
public
:
bool
wordBreak(string s, unordered_set<string> &dict) {
vector<
bool
> wordB(s.length() + 1,
false
);
wordB[0] =
true
;
for
(
int
i = 1; i < s.length() + 1; i++) {
for
(
int
j = i - 1; j >= 0; j--) {
if
(wordB[j] && dict.find(s.substr(j, i - j)) != dict.end()) {
wordB[i] =
true
;
break
;
}
}
}
return
wordB[s.length()];
}
};
|
还有一种字典树的方法,很巧妙,用个vector<bool>记录了是否能从头经过word break走到位置 i。正好练练手写写Trie树试下。http://www.iteye.com/topic/1132188#2402159
Trie树是Node且自身包含Node*的数组,如果数组某个位置不是NULL就代表此处有字符,end表示这里是一个字符串的终结。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
#include <string>
#include <vector>
#include <unordered_set>
using
namespace
std;
class
Node {
public
:
Node* next[26];
bool
end;
Node() : end(
false
) {
for
(
int
i = 0; i < 26; i++) {
next[i] = NULL;
}
}
~Node() {
for
(
int
i = 0; i < 26; i++) {
delete
next[i];
}
}
void
insert(string s) {
int
len = s.length();
Node* cur =
this
;
for
(
int
i = 0; i < len; i++) {
if
(cur->next[s[i] -
'a'
] == NULL) {
cur->next[s[i] -
'a'
] =
new
Node();
}
cur = cur->next[s[i] -
'a'
];
}
cur->end =
true
;
}
};
class
Solution {
public
:
bool
wordBreak(string s, unordered_set<string> &dict) {
Node root;
int
len = s.length();
vector<
bool
> vec(len,
false
);
for
(
auto
it = dict.begin(); it != dict.end(); it++) {
root.insert(*it);
}
findMatch(s, &root, vec, 0);
for
(
int
i = 0; i < len; i++) {
if
(vec[i]) findMatch(s, &root, vec, i + 1);
}
return
vec[len - 1];
}
void
findMatch(
const
string& s, Node* cur, vector<
bool
>& vec,
int
start) {
int
i = start;
int
len = s.length();
while
(i < len) {
if
(cur->next[s[i] -
'a'
] != NULL) {
if
(cur->next[s[i] -
'a'
]->end) { vec[i] =
true
; }
cur = cur->next[s[i] -
'a'
];
}
else
break
;
i++;
}
}
};
|
第二刷:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
class
Solution {
public
:
bool
wordBreak(string s, unordered_set<string> &dict) {
vector<vector<
int
> > canBreak;
// 0 for unvisited, 1 for true, -1 for false
int
N = s.size();
canBreak.resize(N);
for
(
int
i = 0; i < N; i++)
{
canBreak[i].resize(N);
}
return
wordBreakRe(s, dict, canBreak, 0, N - 1);
}
bool
wordBreakRe(string &s, unordered_set<string> &dict, vector<vector<
int
> > &canBreak,
int
start,
int
end)
{
if
(canBreak[start][end] != 0)
return
(canBreak[start][end] == 1 ?
true
:
false
);
string sub = s.substr(start, end - start + 1);
if
(dict.find(sub) != dict.end())
{
canBreak[start][end] = 1;
return
true
;
}
for
(
int
i = start; i < end; i++)
{
if
(wordBreakRe(s, dict, canBreak, start, i) &&
wordBreakRe(s, dict, canBreak, i + 1, end))
{
canBreak[start][end] = 1;
return
true
;
}
}
canBreak[start][end] = -1;
return
false
;
}
};
|