题目描述
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
题目分析
背包问题特征:
是否可以根据一个target,target可能是字符串或者数字,再给定一个容器,问:能否使用容器中的元素做各种排列组合得到 target。
完全背包问题解法:
- 如果是完全背包问题,即容器中的元素可重复使用并且不考虑元素之间顺序,容器放在外循环按序遍历,target在内循环,且内循环正序遍历。
- 如果组合问题需考虑元素之间的顺序,需将 target 放在外循环,将容器放在内循环遍历,且内循环正序。
题目中描述的问题是一个最有组合问题,因此该问题可以使用背包的解题思路。
- 物品:单词数组
- 背包重量:字符串
- 背包价值:单词是否组合成功字符串
由于每个字符串都需所有的单词组合一遍,因此将字符串的循环放到单词数组的循环之前。
- dp[i] 表示以第 i 个字符结尾的字符串是否可以被 wordDict 中组合而成;
- 外层遍历s中每一个与word同长度的字串s.substr(i - len, len) ;
- 内层遍历wordDict每个word。
- 判断 s.substr(i - len, len) == word:
- 若不相等,说明与该 word 不匹配,继续遍历;
- 若相等,说明从 [i - len] 到 i 的字符与 word 匹配。
- dp[i] = dp[i - len] && !s.substr(i - len, len).compare(wordDict[j])
- 对于边界条件,我们定义 dp[0] = true 表示空串且合法。
- 最后返回 dp[s.size()]
Code
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
vector<bool> dp(s.size() + 1, false);
dp[0] = true;
int len = 0;
for(int i = 1; i <= dp.size(); ++i){
for(int j = 0; j < wordDict.size(); ++j){
int len = wordDict[j].length();
if(i >= len) {
dp[i] = dp[i - len] && !s.substr(i - len, len).compare(wordDict[j]);
if (dp[i]) break;
}
}
}
return dp[s.size()];
}
};