单词拆分
题目
给你一个字符串 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
思路
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
//首先这是一个完全背包的问题,因为每一个单词都可以选择多次
//wordDict数组内部的每一个单词就是物品,物品的重量就是单词的长度,背包就是字符串s的长度
/*dp数组的含义,dp[j]表示字符串长度是j的时候,是否可以拆成数组内部的每一个单词的组合
dp[j] 可以是true或者false
*/
/*dp数组的递推公式,运用共是确定的一般方法可以这样看:
如果最后一个单词是wordDict[i], 那么dp[j] = dp[j - wordDict[i].size()] ,其他的情况都是假的
以此类推
*/
//dp数组的初始化,dp[0]是没有意义的,但是为了推导公式,它必须是dp[0] = true;
//为了方便查找建立的集合
unordered_set<string> wordDictmap(wordDict.begin(), wordDict.end());
int bsize = s.size();
vector<int> dp(bsize + 1, false);
dp[0] = true;
//求的是排列数,因为需要在意前后的顺序
for(int j = 1; j <= bsize; j++) {//遍历背包的大小
for(int i = 0; i < j; i++) { //
//因为这里要看s[j - i]是不是存在于s中,所以我们可以用哈希表
string substr = s.substr(i, j - i);
if(wordDictmap.find(substr) != wordDictmap.end() && dp[i]) {
dp[j] = true;
}
}
}
return dp[bsize];
}
};