本文最后更新于:2021年2月28日 晚上
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
- 拆分时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例 1:
| 输入: s = "leetcode", wordDict = ["leet", "code"] 输出: true 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
|
示例 2:
| 输入: s = "applepenapple", wordDict = ["apple", "pen"] 输出: true 解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。 注意你可以重复使用字典中的单词。
|
示例 3:
| 输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: false
|
Solution
参考 @LeetCode官方 、代码随想录
- 暴力回溯,超时
- 时间复杂度 O(n^2^),每个单词都有两个状态,切割和不切割
- 空间复杂度 O(n),算法递归调用系统栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public: bool wordBreak(string s, vector<string>& wordDict) { unordered_set<string> wordSet(wordDict.begin(), wordDict.end()); return go(s, wordSet, 0); }
private: bool go(const string& s, const unordered_set<string>& wordSet, int start) { if (start >= s.size()) { return true; } for (int i = start; i < s.size(); ++i) { string word = s.substr(start, i - start + 1); if (wordSet.find(word) != wordSet.end() && go(s, wordSet, i + 1)) { return true; } } return false; } };
|
- 记忆化搜索
- 技巧,涉及bool状态时,初始化 -1,false 为 0,true 为 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution { public: bool wordBreak(string s, vector<string>& wordDict) { unordered_set<string> wordSet(wordDict.begin(), wordDict.end()); memo = vector<int>(s.size(), -1); return go(s, wordSet, 0); }
private: vector<int> memo;
bool go(const string& s, const unordered_set<string>& wordSet, int start) { if (start >= s.size()) { return true; } if (memo[start] != -1) return memo[start]; for (int i = start; i < s.size(); ++i) { string word = s.substr(start, i - start + 1); if (wordSet.find(word) != wordSet.end() && go(s, wordSet, i + 1)) { memo[start] = 1; return true; } } memo[start] = 0; return false; } };
|
动态规划,转换成 完全背包问题
单词就是物品,字符串s就是背包,单词能否组成字符串s,就是问物品能不能把背包装满。
递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) { dp[i] = true }
考虑 遍历顺序
时间复杂度:O(n^3),因为substr返回子串的副本是O(n)的复杂度(这里的n是substring的长度)
空间复杂度:O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public: bool wordBreak(string s, vector<string>& wordDict) { unordered_set<string> wordSet; for(auto word : wordDict) wordSet.insert(word);
vector<bool> dp(s.size()+1); dp[0] = true; for(int i=1; i<=s.size(); ++i){ for(int j=0; j<i; ++j){ if(dp[j] && wordSet.find(s.substr(j,i-j))!=wordSet.end()){ dp[i] = true; break; } } } return dp[s.size()]; } };
|