leetcode 139 单词拆分(word break)
一开始的错误答案与错误思路,幻想直接遍历得出答案:
1 class Solution { 2 public: 3 bool wordBreak(string s, vector<string>& wordDict) { 4 for(int i;i<s.size();i++){ 5 int step=0; 6 for(int j;j<wordDict.size();j++){ 7 if(s.substr(i,wordDict[j].size())==wordDict[j]){ 8 step=wordDict[j].size();break; 9 } 10 } 11 if(step==0) return false; 12 i+=step; 13 } 14 return true; 15 } 16 };
这种做法其实方向比较对,但是离正确答案还差一步,这里的step的更新是唯一的,而现实的情况可能同时满足几种不同的step,所以该程序可以通过测试用例"leetcode"
["leet","code"],但是不能通过"cars" ["car","ca","rs"]。所以我们需要想办法吧所有的step下的情况都存起来以供后面查找。但由于这样往后推是树状发散的,结果可能很多;
现在采用dp数组,如果前i个字母可以被拆分,则dp[i]==true否则dp[i]==false,然后令i++,对i+1的验证则是从j=i-maxlenth开始搜索(maxlenth为字典最长的单词长度),如果dp[j]==true且后面的j+1到i+1字典中有,说明i+1可被拆分,dp[i]==true;依次类推,代码如下:
1 class Solution { 2 public: 3 bool wordBreak(string s, vector<string>& wordDict) { 4 vector<bool> dp(s.size()+1,false); 5 dp[0]=true; 6 unordered_set<string> m(wordDict.begin(),wordDict.end()); 7 //获取最大wordDict的长度 8 int maxlen=0; 9 for(int i=0;i<wordDict.size();i++){ 10 //maxlen=maxlen>wordDict[i].size()? maxlen : wordDict[i].size(); 11 if(maxlen<wordDict[i].size()) maxlen=wordDict[i].size(); 12 } 13 //遍历s,依次找到前i个字母能否被partition 14 for(int i=1;i<=s.size();++i){ 15 for(int j=max(i-maxlen,0);j<i;++j){ 16 //假如前j个字母能被拆分,而第j到第i个字母字典恰好又有,dp[i]为正确 17 if(dp[j]&& m.find(s.substr(j,i-j))!=m.end()){ 18 dp[i]=true;break; 19 } 20 } 21 } 22 return dp[s.size()]; 23 } 24 };