[leetcode]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".
转载请注明原创:http://www.cnblogs.com/StartoverX/p/4604668.html
分析:输入是一个unordered-set<string>& wordDict,一个string& s,输出是一个bool值,判断string s是否能被分解成wordDict中的string值。
分析该问题我们发现,如果s能够被分解成wordDict中的单词组合,那么,对于其分割答案中的一次分割s->s1,s2,将s分割成s1和s2,s1和s2必也能分割成wordDict中的单词。也就是对s的分割包含了对s1和s2的分割,该问题的最优解包含了其子问题的最优解,该问题具有最优子结构性质。
现在我们可以尝试通过递归的方法求解该问题,我们对于s中每两个字符间的每一次分割遍历s,如果分割得到的s1和s2都能被分解为wordDict中的单词,我们就说s能够被分解为wordDict中的单词,如果s1和s2不能被分解为wordDict中的单词,则继续遍历s。如果分割点直到s中的最后一个字符都没能得到两个都能被分解的s1和s2,则我们说s不能分解为s1和s2中的单词。
#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <algorithm>
using namespace std;
class Solution
{
public:
bool wordBreak(string s,unordered_set<string>& wordDict)
{
if(wordDict.size() == 0) //边界条件1
{
return false;
}
if(s.size() == 0) //边界条件2
{
return false;
}
if(find(wordDict.begin(),wordDict.end(),s) != wordDict.end()) //递归退出条件
{
return true;
}
int size = s.size();
if(size == 1) //如果wordDict中没找到s,s又不能继续分割,return false
{
return false;
}
for(int i=1;i<size;i++) //对s遍历每一个分割点
{
string s1 = s.substr(0,i);
string s2 = s.substr(i,size);
if(wordBreak(s1,wordDict) && wordBreak(s2,wordDict))
{
return true;
}
}
return false;
}
};
分析上述递归的方法,我们发现,对于每一个s,我们都要遍历它的每两个字符间的分割点,而s分割出来的s1,s2,又包含了同样的字符顺序,也就是,我们重复求解了很多次相通的字符串,所以,上面的递归解法非常的低效。由于我们判断出该题的子问题相互重叠,我们使用动态规划的方法。
上面已经得到了一个递归解法,所以在动态规划解法中我们使用带备忘的自顶向下法对于此问题,我们要求的解是对于一个特定的string,求对应的bool值,所以我们使用一个全局map:map<string,bool> mp来保存每次的结果。在每次递归前检查是否已经取得了解,并在递归后在map中保存解。
#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <algorithm>
#include <map>
using namespace std;
class Solution
{
public:
map<string,bool> mp;
bool wordBreak(string s,unordered_set<string>& wordDict)
{
if(wordDict.size() == 0) //边界条件1
{
return false;
}
if(s.size() == 0) //边界条件2
{
return false;
}
if(find(wordDict.begin(),wordDict.end(),s) != wordDict.end()) //递归退出条件
{
return true;
}
int size = s.size();
if(size == 1) //如果wordDict中没找到s,s又不能继续分割,return false
{
return false;
}
for(int i=1;i<size;i++) //对s遍历每一个分割点
{
string s1 = s.substr(0,i);
string s2 = s.substr(i,size);
bool flag1 = false;
bool flag2 = false;
bool is1 = false;
bool is2 = false;
if(mp.empty() == false && (mp.find(s1) != mp.end()))//如果已经得到了s1的解,直接从mp中取。
{
is1 = true;
flag1 = (*mp.find(s1)).second;
}
if(mp.empty() == false && (mp.find(s2) != mp.end()))//如果已经得到了s2的解,直接从mp中取。
{
is2 = true;
flag2 = (*mp.find(s2)).second;
}
if(is1 == false)//如果没有得到过s1的解,求解并保存在mp中。
{
flag1 = wordBreak(s1,wordDict);
mp[s1] = flag1;
}
if(is2 == false)//如果没有得到过s2的解,求解并保存在mp中。
{
flag2 = wordBreak(s2,wordDict);
mp[s2] = flag2;
}
if(flag1 && flag2)
{
return true;
}
}
return false;
}
};