140. Word Break II

题目描述

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences.
Note:
The same word in the dictionary may be reused multiple times
in the segmentation.
You may assume the dictionary does not contain duplicate
words.
Example 1:
Input:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
Output:
[
"cats and dog",
"cat sand dog"
]
Example 2:
Input:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
Output:
[
"pine apple pen apple",
"pineapple pen apple",
"pine applepen apple"
]
Explanation: Note that you are allowed to reuse a dictionary
word.
Example 3:
Input:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
Output:
[]

方法1

思路

递归版本:为了防止重复计算,使用了一个映射保存中间的对子串的递归函数调用结果(这是一种比较原始的利用动态规划的思想解决问题想法:利用映射保存中间结果,随时得到已有的结果)
LeetCode耗时20ms,内存消耗12MB

代码实现

class Solution {
public:
    vector<string> wordBreak(string s, vector<string> wordDict) {

        unordered_set<string> dict(wordDict.begin(),wordDict.end());
        int n=s.length();
        int minLen = n;
        int maxLen = 0;       
        for(auto word:dict)
        {
            int temp = word.length();
            minLen = min(minLen,temp);
            maxLen = max(maxLen,temp);
        }
        unordered_map<string,vector<string>> m;
        return wordBreakCore(dict,minLen,maxLen,s,m);       
    }
    //注意,这里的递归函数设计为返回值为结果
    vector<string> wordBreakCore(unordered_set<string> &dict,int minLen,int maxLen,string s,unordered_map<string,vector<string>> &m)
    {
        if(m.find(s)!=m.end())
            return m[s];
        vector<string> ret;
        // 不进行分割
        if(dict.find(s)!=dict.end())
            ret.push_back(s);
        
        // 枚举进行分割的情况       
        for(int l = minLen; l<s.length() && l<=maxLen; l++)
        {
            string left = s.substr(0,l);
            if(dict.find(left)!=dict.end())
            {
               vector<string> right = wordBreakCore(dict,minLen,maxLen,s.substr(l),m);
                // 可以成功分割
               if(right.size() > 0)
               {
                   for(auto str : right){
                       ret.push_back(left+" "+str);
                   }
               } 
            }
        }
        m[s] = ret;        
        return ret;
    }
};

方法2

思路

深度优先遍历,思路:DFS+利用动态规划得到的信息剪枝(能否划分),剪枝就是避免没有意义的递归的调用。
leetcode耗时12ms,内存消耗9.8MB

代码实现

class Solution {
public:
    vector<string> wordBreak(string s, vector<string>& wordDict) {

        unordered_set<string> dict(wordDict.begin(),wordDict.end());
        int n=s.length();
        vector<bool> dp(n+1,false);
        dp[n] = true;//要合理的初始化使之满足递推公式的要求
        int minLen = n;
        int maxLen = 0;       
        for(auto word:dict)
        {
            int temp = word.length();
            minLen = min(minLen,temp);
            maxLen = max(maxLen,temp);
        } 
        //这里的dp是从右边到左边递推保存信息,是为了下面
        //调用递归函数方式的需要
              //i+minLen==n,0+n==n
        for(int i=n-minLen;i>=0;i--)
        {
            for(int l=minLen;l<=maxLen && i+l<=n;l++)
            {
                if(dict.find(s.substr(i,l))!=dict.end() && dp[i+l])
                {
                  dp[i] = true;
                  break;
                }
            }
        }
        vector<string> ret;
        if(dp[0] == false)
            return ret;
        dfs(dict,minLen,maxLen,dp,s,0,"",ret);
        return ret;
    }
    //深度优先遍历,这里函数的返回类型为void,函数的接口参数cur
    //设计为携带遍历过程中,从左到右的到这个位置为止的
    //前半部分信息(也就是dfs所经过的路径分割元素拼接),如果函数
    //接口设计为有返回值,则返回值为整个结果
    void dfs(unordered_set<string> &dict, int minLen, int maxLen,vector<bool> &dp, string &s, int index,string cur,vector<string> &ret)
    {
        for(int l = minLen; l<=maxLen && l+index<=s.size();l++)
        {
            if(dict.find(s.substr(index,l))!=dict.end() && dp[index+l]) 
            {   //这里只是为了拼接的需要,人为的将常见的dfs
                //的递归终止情况提前到这里
                if(index+l == s.size())//最后一个单词的情况 
                    ret.push_back(cur+s.substr(index,l));
                else//注意这里的拼接技巧,还不到最后一个单词的话,每一个单词后面加" ",遇到最后一个单词,只拼接单词,不加" "
                    dfs(dict,minLen,maxLen,dp,s, index+l,cur+s.substr(index,l)+" ",ret);
            }
        }
    }
};

posted on 2021-05-02 23:19  朴素贝叶斯  阅读(42)  评论(0编辑  收藏  举报

导航