首页 > 代码库 > leetcode day7 -- Word Break I II
leetcode day7 -- Word Break I II
Word Break
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"
.
分析:先以最短的划分,先判断以最短的开头是否能分成词,递归判断。但是出现超时如下:
代码1:超时的代码
Last executed input:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab", ["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"]
class Solution{ public: bool wordBreak(string s, unordered_set<string> &dict) { if(s.empty() || dict.empty()){ return false; } return wordBreak(s,0,dict); } bool wordBreak(string s,int start,unordered_set<string>& dict){ for(int i=start; i<s.length();++i){ if(dict.find(s.substr(start,i-start+1))!=dict.end()){ if(i+1==s.length()||wordBreak(s,i+1,dict)){ return true; } } } return false; } };
代码2、上述超时原因很明显,是每次判断最短的,判断次数太多,那么如何减少这个判断次数呢?如果从最长判断还是会出现这种判断次数太多的结果。
有点无从下手,搜索参考http://www.cnblogs.com/easonliu/p/3654123.html,其中应用了动态规划的方法。
思路:用vector<bool> dp来保存字符串位置i及以前的字符串能否被分解为单词,如果dp[i]==true,则判断i后面的长度为len的字串能否被分解为单词,更新dp[i+len]。这样避免了子问题多次求解的问题。
代码如下:
class Solution { public: bool wordBreak(string s, unordered_set<string> &dict) { int n = (int)s.size(); vector<bool> dp(n + 1, false); dp[0] = true; for (int i = 0; i < n; i++) { if (dp[i]) { for (int len = 1; i + len - 1 < n; len++) { if (dict.count(s.substr(i, len)) > 0) dp[i + len] = true; } } } return dp[n]; } };
修改:
上述代码需要遍历结束所有的,其实只要有一个满足条件就可以了,就是当其中一个i和len满足i+len == n并且dict.count(s.substr(i, len))>0时即可,这样运行时间要短一些。
如下:
class Solution { public: bool wordBreak(string s, unordered_set<string> &dict) { int n = (int)s.size(); vector<bool> dp(n + 1, false); dp[0] = true; for (int i = 0; i < n; i++) { if (dp[i]) { for (int len = 1; i + len - 1 < n; len++) { if (dict.count(s.substr(i, len)) > 0) { if( i+len == n){ return true; } dp[i + len] = true; } } } } return dp[n]; } };
2、Word Break II
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.
Return all such possible sentences.
For example, given
s = "catsanddog"
,
dict = ["cat", "cats", "and", "sand", "dog"]
.
A solution is ["cats and dog", "cat sand dog"]
.
分析:此题和上题类似,也可以采用动态规划的方法。
代码1:超内存的代码。用vector来保存截止到每个位置之前可以分解为单词的所有组合,但是这样耗费内存太多。
Memory Limit Exceeded
class Solution { public: vector<string> wordBreak(string s, unordered_set<string> &dict) { int n = (int)s.size(); vector<bool> dp(n + 1, false); vector<vector<string>> allWords(n+1); dp[0] = true; for (int i = 0; i < n; i++) { if (dp[i]) { vector<string> tempVector = allWords[i]; for (int len = 1; i + len - 1 < n; len++) { string subStr = s.substr(i, len); if (dict.count(subStr) > 0) if(allWords[i].empty()){ allWords[i+len].push_back(subStr); }else{ for(int j=0; j<allWords[i].size();++j){ allWords[i+len].push_back(allWords[i][j]+" "+subStr); } } dp[i + len] = true; } } } return allWords[n]; } };
那么如何节约内存呢?想着记录每个点的前一个分割点的值,然后遍历得到所有可能的值,但是如何输出感觉不容易。。。
先附上一个搜到的通过的代码,后续再来补讲解。
class Solution { public: vector<string> wordBreak(string s, unordered_set<string> &dict) { int n=s.length(); vector<vector<bool> > match(n+1,vector<bool>(n+1,false)); for(int i=0;i<=n;i++) match[0][i]=true; for(int len=1;len<=n;len++) { for(int start=0;start+len<=n;start++) { string tmp=s.substr(start,len); if(dict.count(tmp)>0) match[len][start]=true; else { for(int left=1;left<len;left++) { match[len][start]=match[left][start]&&match[len-left][start+left]; if(match[len][start]) break; } } } } if(match[n][0]==false) return vector<string>(); vector<string> ans; vector<string> had; dfs(s,0,match,had,ans,dict); return ans; } void dfs(string& s,int k,vector<vector<bool> >& match,vector<string>& had,vector<string>& ans,unordered_set<string> &dict) { int n=s.length(); if(k>=n) { if(!had.empty()) { string ret; for(int i=0;i<had.size();i++) { ret.append(had[i]); if(i!=had.size()-1) ret.push_back(‘ ‘); } ans.push_back(ret); return; } } for(int len=1;k+len<=n;len++) { string tmp=s.substr(k,len); if(dict.count(tmp)>0 && match[n-k-len][k+len]) { had.push_back(tmp); dfs(s,k+len,match,had,ans,dict); had.pop_back(); } } } };
leetcode day7 -- Word Break I II