先上自己的代码
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 ; } }; |