【LeetCode-动态规划】单词拆分
题目描述
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
- 拆分时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例:
输入: s = "leetcode", wordDict = ["leet", "code"] 输出: true 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。 输入: s = "applepenapple", wordDict = ["apple", "pen"] 输出: true 解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。 ? 注意你可以重复使用字典中的单词。 输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: false
题目链接: https://leetcode-cn.com/problems/word-break/
思路1
使用动态规划来做。
- 状态定义:使用 dp[i] 表示从字符串头开始长度为 i 的字符串是否能被拆分为字典中的单词,令边界条件dp[0]=true。例如,对于例子
s = "leetcode", wordDict = ["leet", "code"]
来说,dp[4]=true,因为 leet 在 wordDict 中。 - 状态转移公式:dp[i] = dp[j] && (s[j,...,i] in wordDict),j 在 [0, i-1] 之间。还拿上一个例子来说,我们要判断 dp[4] 的值,我们可以看:
- dp[3] && ("t" in wordDict);
- dp[2] && ("et" in wordDict);
- dp[1] && ("eet" in wordDict);
- dp[0] && ("leet" in wordDict);
只要这 4 种情况有一种为 true,则说明 "leet" 能被拆分,所以 dp[4]=true。
代码如下:
class Solution { public: bool wordBreak(string s, vector<string>& wordDict) { unordered_set<string> lookup(wordDict.begin(), wordDict.end()); vector<bool> dp(s.size()+1, false); dp[0] = true; for(int i=1; i<=s.size(); i++){ for(int j=i-1; j>=0; j--){ dp[i] = dp[j] && (lookup.count(s.substr(j, i-j))!=0); if(dp[i]) break; } } return dp[s.size()]; } };
- 时间复杂度:O(n^2)
- 空间复杂度:O(n)
思路2
使用回溯来做。代码如下:
class Solution { bool ans = false; public: bool wordBreak(string s, vector<string>& wordDict) { int start = 0; unordered_set<string> lookup(wordDict.begin(), wordDict.end()); dfs(s, start, lookup); return ans; } void dfs(string s, int start, unordered_set<string> lookup){ if(start>=s.size()){ ans = true; return; } if(ans) return; for(int i=start+1; i<=s.size(); i++){ // 注意是 i<=s.size(),不是 i<s.size() if(lookup.count(s.substr(start, i-start))>0){ dfs(s, i, lookup); } } } };
思路3
备忘录算法。我们使用一个备忘录unordered_map<string, bool> memo
对思路 2 进行改进,也就是记录下那些不成功的子串分割,如果遇到之前出现的子串并有不成功的记录就不用往下递归了。代码如下:
class Solution { bool ans = false; public: bool wordBreak(string s, vector<string>& wordDict) { int start = 0; unordered_set<string> lookup(wordDict.begin(), wordDict.end()); unordered_map<string, bool> memo; // 备忘录 dfs(s, start, lookup, memo); return ans; } void dfs(string s, int start, unordered_set<string> lookup, unordered_map<string, bool>& memo){ if(start>=s.size()){ ans = true; return; } if(ans) return; for(int i=start+1; i<=s.size(); i++){ // 注意是 i<=s.size(),不是 i<s.size() string sub = s.substr(start, i-start); if(lookup.count(sub)>0){ if(memo.count(sub)==0 || memo[sub]!=false) dfs(s, i, lookup, memo); } memo[sub] = false; // 这样分割不行,记录下来不成功的子串 } } };
相关推荐
yedaoxiaodi 2020-07-26
Eduenth 2020-06-22
Oudasheng 2020-06-13
sunjunior 2020-05-19
chenfei0 2020-04-30
老和山下的小学童 2020-04-20
SystemArchitect 2020-04-14
jiayuqicz 2020-02-02
zangdaiyang 2020-01-25
yuanran0 2020-01-20
yedaoxiaodi 2020-01-12
rein0 2020-01-01
Oudasheng 2019-12-27
Oudasheng 2019-12-22
wuxiaosi0 2019-12-17
trillionpower 2019-11-23
ustbfym 2019-11-03
yaohustiAC 2019-10-28