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

 

posted @ 2015-06-27 21:02  TimCheng  阅读(250)  评论(0编辑  收藏  举报