[LeetCode] 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.html

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:app

Input:
s = ""
wordDict = 
Output:

catsanddog["cat", "cats", "and", "sand", "dog"][
  "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:post

Input:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
Output:
[]

 

这道题是以前那道Word Break 拆分词句的拓展,那道题只让咱们判断给定的字符串可否被拆分红字典中的词,而这道题加大了难度,让咱们求出全部能够拆分红的状况,就像题目中给的例子所示。以前的版本中字典wordDict的数据类型是HashSet,如今的不知为什么改为了数组vector,并且博主看到第二个例子就笑了,PPAP么,哈哈~优化

根据老夫行走江湖多年的经验,像这种返回结果要列举全部状况的题,十有八九都是要用递归来作的。当咱们一时半会没有啥思路的时候,先不要考虑代码如何实现,若是就给你一个s和wordDict,不看Output的内容,你会怎么找出结果。好比对于例子1,博主可能会先扫一遍wordDict数组,看有没有单词能够当s的开头,那么咱们能够发现cat和cats均可以,好比咱们先选了cat,那么此时s就变成了 "sanddog",咱们再在数组里找单词,发现了sand能够,最后剩一个dog,也在数组中,因而一个结果就出来了。而后回到开头选cats的话,那么此时s就变成了 "anddog",咱们再在数组里找单词,发现了and能够,最后剩一个dog,也在数组中,因而另外一个结果也就出来了。那么这个查询的方法很适合用递归来实现,由于s改变后,查询的机制并不变,很适合调用递归函数。再者,咱们要明确的是,若是不用记忆数组作减小重复计算的优化,那么递归方法跟brute force没什么区别,大几率没法经过OJ。因此咱们要避免重复计算,如何避免呢,仍是看上面的分析,若是当s变成 "sanddog"的时候,那么此时咱们知道其能够拆分红sand和dog,当某个时候若是咱们又遇到了这个 "sanddog"的时候,咱们难道还须要再调用递归算一遍吗,固然不但愿啦,因此咱们要将这个中间结果保存起来,因为咱们必需要同时保存s和其全部的拆分的字符串,那么可使用一个HashMap,来创建两者之间的映射,那么在递归函数中,咱们首先检测当前s是否已经有映射,有的话直接返回便可,若是s为空了,咱们如何处理呢,题目中说了给定的s不会为空,可是咱们递归函数处理时s是会变空的,这时候咱们是直接返回空集吗,这里有个小trick,咱们其实放一个空字符串返回,为啥要这么作呢?咱们观察题目中的Output,发现单词之间是有空格,而最后一个单词后面没有空格,因此这个空字符串就起到了标记当前单词是最后一个,那么咱们就不要再加空格了。接着往下看,咱们遍历wordDict数组,若是某个单词是s字符串中的开头单词的话,咱们对后面部分调用递归函数,将结果保存到rem中,而后遍历里面的全部字符串,和当前的单词拼接起来,这里就用到了咱们前面说的trick。for循环结束后,记得返回结果res以前创建其和s之间的映射,方便下次使用,参见代码以下:url

 

解法一:spa

class Solution {
public:
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        unordered_map<string, vector<string>> m;
        return helper(s, wordDict, m);
    }
    vector<string> helper(string s, vector<string>& wordDict, unordered_map<string, vector<string>>& m) {
        if (m.count(s)) return m[s];
        if (s.empty()) return {""};
        vector<string> res;
        for (string word : wordDict) {
            if (s.substr(0, word.size()) != word) continue;
            vector<string> rem = helper(s.substr(word.size()), wordDict, m);
            for (string str : rem) {
                res.push_back(word + (str.empty() ? "" : " ") + str);
            }
        }
        return m[s] = res;
    }
};

 

咱们也能够将将主函数自己看成递归函数,这样就不用单独的使用一个递归函数了,不过咱们的HashMap必须是全局了,写在外部就行了,参见代码以下:code

 

解法二:htm

class Solution {
public:
    unordered_map<string, vector<string>> m;
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        if (m.count(s)) return m[s];
        if (s.empty()) return {""};
        vector<string> res;
        for (string word : wordDict) {
            if (s.substr(0, word.size()) != word) continue;
            vector<string> rem = wordBreak(s.substr(word.size()), wordDict);
            for (string str : rem) {
                res.push_back(word + (str.empty() ? "" : " ") + str);
            }
        }
        return m[s] = res;
    }
};

 

相似题目:

Word Break

Concatenated Words

 

参考资料:

https://leetcode.com/problems/word-break-ii/description/

https://leetcode.com/problems/word-break-ii/solution/

https://leetcode.com/problems/word-break-ii/discuss/44167/My-concise-JAVA-solution-based-on-memorized-DFS

 

LeetCode All in One 题目讲解汇总(持续更新中...)

相关文章
相关标签/搜索