https://leetcode-cn.com/problems/word-break/
解法一、回溯
依照惯例,没有好的思路的时候,就先想想暴力解法怎么做。暴力解法无非是逐个单词地拆分字符串,每次选的单词可以重复。要实现暴力解法的话,肯定就是用回溯,因为回溯算法“撤销选择”的特点,保证了每次都能考虑到所有的单词。
简而言之,对于字符串s和单词word,word长度为n,当word与s[:n]相同时,就可以把word选来进行一次拆分,紧接着继续判断s[n:]是否能被拆分。当s被拆分到长度为0时,回溯算法就找到了答案。
回溯算法是一种穷举法,其时间复杂度自然就会比较高,要使其变得高效的话,采用剪枝是必需的。本题中我们如何剪枝呢?剪枝可以是剪掉那些一定不会得到解的分支,这我们在判断word == s[:n]时就进行了;剪枝也可以是剪掉重复的分支,我们尚未进行。考虑对于s = "leetcode"
和单词leet, code, 'le', 'et'
,选用leet
后会进行backtrack("code")
,但当我们依次选用'le'
和'et'
后,又会进行backtrack("code")
,这就存在了重复的分支(因为字典中的单词可以重复使用,即选择列表始终是相同的,只有要判断的s不同)。
要实现这种剪枝也容易,判断backtrack("s")
是否被执行过即可。
代码
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> set;
backtrack(s, wordDict, set);
return result;
}
private:
bool result = false;
void backtrack(string