LeetCode_Word Break
2014-07-06 19:55
232 查看
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 =
dict =
Return true because
之前好像是写过这个题目的解题报告,说实话这个题目我实在是理解了好久。今天花了一整天时间研究这个题目,最终自己给出了一个O(n^3)的dp算法,然后在Discuss中看了各路大神们的算法,我真是太。。。
话不多说,正题:
思路1:dfs
深度优先搜素,对于字符串s[0,..,n]每次判断其前缀是否可以按照字典所给出的单词进行分词操作,递归进行,分词之字符串尾时返回,代码如下:
dfs有太多的重复计算,具体图例在我第一遍作的时候就已经画图了,因此想到dp:
思路2:dp
我自己的想法是,对于字符串s[i,..,j]是否可以按照字典所给单词进行分词,存在以下两种情况:
1) s[i,..,j]在字典dict中;
2) 至少存在一个k(i<k<j)使得s[i,..,k]和s[k+1,..,j]都可以被分词;
为此使dp[i][j]表示s[i,..,j]是否可以被分词,递归式如下:
dp[i][j] = true if dictContain(s[i,..,j]) or (dictContain(s[i,..,k])&&dictContain(s[k+1,..,j]))
= false other
由此,有点类似于矩阵连乘问题,共有O(n^2)个子问题,每个子问题有包括O(n)种选择,算法时间复杂度O(n^3),空间复杂度O(n^2)。
代码如下:
思路3:dp+dfs
看了一位大神的代码,总结一下,发现其实换个角度,我们只需要考虑s[0,..,i]是否可以被分词,s[0,..,j]可以被分词的充分必要条件是:
1)存在一个k(0<k<i)使得s[0,..,k]可以被分词并且s.substr(k+1,j)是字典dict中的单词 OR
2)s[0,..,j]本身就在字典dict中;
由此每个子问题的子问题变为只有1个,同时对于子问题的选择有O(n)种,为此使用数组
dp[0,s.size()]记录分词信息,其中dp[i]表示s[0,..,i]是否可以被分词,
dp[i] = true if dictContain(s[0,..,i]) or ((dictContain(s[k+1,..,j]))&&dp[k])
最终结果为dp[s.size()-1],时间复杂度O(n^2),空间O(n),代码如下:
最后说一句忘了在哪个文章中看到的一句话:dp真是一个神奇的东西,只有你自己写了才能体会到,dp代码的简洁美
For example, given
s =
"leetcode",
dict =
["leet", "code"].
Return true because
"leetcode"can be segmented as
"leet code".
之前好像是写过这个题目的解题报告,说实话这个题目我实在是理解了好久。今天花了一整天时间研究这个题目,最终自己给出了一个O(n^3)的dp算法,然后在Discuss中看了各路大神们的算法,我真是太。。。
话不多说,正题:
思路1:dfs
深度优先搜素,对于字符串s[0,..,n]每次判断其前缀是否可以按照字典所给出的单词进行分词操作,递归进行,分词之字符串尾时返回,代码如下:
//递归求解每次检查当前字串前缀,如果可分则继续深度查询 class Solution { public: bool wordBreak(string s, unordered_set<string> &dict) { issegment=false; wordBreak(s,0,dict); return issegment; } void wordBreak(const string &s,int pos,unordered_set <string> &dict){ if(pos==s.size()) issegment=true; if(issegment) return; for(int i=pos;i<s.size();i++){ auto iter=dict.find(s.substr(pos,i-pos+1)); if(iter!=dict.end()){ wordBreak(s,i+1,dict); } } } private: bool issegment; };
dfs有太多的重复计算,具体图例在我第一遍作的时候就已经画图了,因此想到dp:
思路2:dp
我自己的想法是,对于字符串s[i,..,j]是否可以按照字典所给单词进行分词,存在以下两种情况:
1) s[i,..,j]在字典dict中;
2) 至少存在一个k(i<k<j)使得s[i,..,k]和s[k+1,..,j]都可以被分词;
为此使dp[i][j]表示s[i,..,j]是否可以被分词,递归式如下:
dp[i][j] = true if dictContain(s[i,..,j]) or (dictContain(s[i,..,k])&&dictContain(s[k+1,..,j]))
= false other
由此,有点类似于矩阵连乘问题,共有O(n^2)个子问题,每个子问题有包括O(n)种选择,算法时间复杂度O(n^3),空间复杂度O(n^2)。
代码如下:
#include <string> #include <vector> using namespace std; class Solution{ public: bool wordBreak(string s,unordered_set <string> &dict){ int len=s.size(); if(!len){ return false; } vector <vector <bool> > dp(len,vector <bool>(len,0)); //initialize dp for(int i=0;i<len;i++){ dp[i][i]=dictContain(s.substr(i,1),dict); } //dp for(int l=2;l<=len;l++){ for(int beg=0;beg+l<=len;beg++){ dp[beg][beg+l-1]=dictContain(s.substr(beg,l),dict); if(dp[beg][beg+l-1]){continue;} for(int k=1;k<l;k++){ dp[beg][beg+l-1]=dp[beg][beg+k-1]&&dp[beg+k][beg+l-1]; if(dp[beg][beg+l-1]) break; } } } return dp[0][len-1]; } bool dictContain(const string &s,const unordered_set <string> &dict){ auto iter=dict.find(s); if(auto==dict.end()){ return false; } return true; } }
思路3:dp+dfs
看了一位大神的代码,总结一下,发现其实换个角度,我们只需要考虑s[0,..,i]是否可以被分词,s[0,..,j]可以被分词的充分必要条件是:
1)存在一个k(0<k<i)使得s[0,..,k]可以被分词并且s.substr(k+1,j)是字典dict中的单词 OR
2)s[0,..,j]本身就在字典dict中;
由此每个子问题的子问题变为只有1个,同时对于子问题的选择有O(n)种,为此使用数组
dp[0,s.size()]记录分词信息,其中dp[i]表示s[0,..,i]是否可以被分词,
dp[i] = true if dictContain(s[0,..,i]) or ((dictContain(s[k+1,..,j]))&&dp[k])
最终结果为dp[s.size()-1],时间复杂度O(n^2),空间O(n),代码如下:
class Solution{ public: bool wordBreak(string s,unordered_set <string> &dict){ int len=s.size(); vector <bool> dp(len+1,0); dp[0]=true; for(int i=1;i<=len;i++){ //check if s.substr(0,i) can be broken string str=s.substr(0,i); for(int j=0;j<i;j++){ if(dp[j]&&dictContain(str,dict)){ dp[i]=true; break; } str.erase(str.begin()); } } return dp[len]; } bool dictContain(string s,const unordered_set <string> &dict){ auto iter=dict.find(s); if(iter!=dict.end()){ return true; } return false; } } ;
最后说一句忘了在哪个文章中看到的一句话:dp真是一个神奇的东西,只有你自己写了才能体会到,dp代码的简洁美
相关文章推荐
- [LeetCode] Word Break
- 【LeetCode-面试算法经典-Java实现】【139-Word Break(单词拆分)】
- leetcode:Word Break
- LeetCode(139)Word Break
- 【leetcode】Word Break
- 【Leetcode】Word Break
- Leetcode 139, Word Break
- 每天一道算法题(五)Leetcode – Word Break (Java)
- LeetCode *** 139. Word Break
- [Leetcode] Word Break、Word BreakII
- 【LeetCode笔记】Word Break
- 动态规划——Word Break 拆分词句【LeetCode】
- 【LeetCode】139. Word Break
- leetcode 139. Word Break
- [Leetcode] word break 拆分词语
- [LeetCode] Word Break 拆分词句
- [leetcode]139. Word Break(Java)
- Leetcode: Word Break
- LeetCode题解:Word Break
- 【LeetCode从零单排】No198.House Robber &&No91.Decode Ways&&139 word break(动态规划典型应用)