[leetcode]Word Break

先上自己的代码

 

 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 ;
     }
};

  

转载于:https://www.cnblogs.com/forcheryl/p/3997304.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值