代码随想录算法训练营第四十六天| 139.单词拆分

LeetCode 139.单词拆分

链接: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& wordDict) {
        // 定义下标:dp[i]表示长度为i的子字符串能否用wordDict拼接出
        vector dp(s.size() + 1, false);
        dp[0] = true;
        unordered_set 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()];
    }
};

你可能感兴趣的:(代码随想录算法训练营,算法,leetcode,动态规划)