LeetCode 139.单词拆分
思路:
看到单词拆分很容易想到之前做回溯题目的时候,用回溯的办法给单词做拆分判断是否为回文,本题同样可以用回溯暴力搜索出来,每次拆分后对比wordDict看是否在里面,但是这样的话非常容易超时,所以需要用动态规划的办法。
wordDict里每个单词可以使用多次,所以是完全背包。定义下标:dp[i]表示长度为i的子字符串能否用wordDict拼接出,然后根据定义初始化dp。默认情况下dp数组都是false,都是不能表示,只有dp[0]=true,因为长度为0的空字符一定可以表示出来。然后是确认递归公式,首先要在s中切割一段字符串,然后拿到wordDict中去匹配,切割的长度需要跟wordDict中单词wordDict[i]长度一致,因为无论超出长度或者低于长度,都不可能与wordDict[i]匹配成功,如果匹配成功,dp[j]就更新为true,但同时也要保证匹配wordDict[i]之前的都要成功,所以还需要加一个条件,即dp[j - wordDict[i].size()]也必须为true。
最后递推公式为:dp[j] = hashset.find(word) != hashset.end() && dp[j - wordDict[i].size()]。然后我们要在更新过的dp[j]和之前的dp[j]中选取一个“最大值”,也就是进行“或”的操作,如果两者任意一个为true,则dp[j]为true。
最后确定遍历顺序,这题中先遍历背包还是先遍历物品都可以。
代码:
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
// 定义下标:dp[i]表示长度为i的子字符串能否用wordDict拼接出
vector<bool> dp(s.size() + 1, false);
dp[0] = true;
unordered_set<string> hashset(wordDict.begin(), wordDict.end());
// 完全背包,先遍历背包
for (int j = 0; j <= s.size(); j++)
{
for (int i = 0; i < wordDict.size(); i++)
{
if (j >= wordDict[i].size())
{
string word = s.substr(j - wordDict[i].size(), wordDict[i].size());
if (dp[j] == false)
dp[j] = hashset.find(word) != hashset.end() && dp[j - wordDict[i].size()];
}
}
}
return dp[s.size()];
}
};