【LeetCode】139. 单词拆分

139. 单词拆分(中等)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 思路

    • 首先将大问题分解成小问题:
      • 前 i 个字符的子串,能否分解成单词;
      • 剩余子串,是否为单个单词;
    • 动态规划的四个步骤:
      1. 确定 dp 数组以及下标的含义

        dp[i] 表示 s 的前 i 位是否可以用 wordDict 中的单词表示。

      2. 确定递推公式

        如果 dp[j] == true,且 [j, i] 这个区间的子串出现在字典里,那么 dp[i] 一定是true。

        所以可以确定递推公式:if([j,i] 这个区间的子串出现在字典里 && dp[j] == true) dp[i] = true;

      3. dp 数组初始化

        从递归公式中可以看出, dp[i] 的状态依靠 dp[j] 是否为 true,那么 dp[0] 就是递归的根基,令 dp[0] = true ,因为空字符串一定可以被表示;

      4. 确定遍历顺序

        题目中说是拆分为一个或多个在字典中出现的单词,所以这是完全背包问题,需要讨论两层 for 循环的前后顺序。 本周小结!(动态规划系列五)

        如果求组合数就是外层 for 循环遍历物品,内层 for 循环遍历背包;
        如果求 排序数就是外层 for 循环遍历背包,内层 for 循环遍历物品。

        由于本题要求的是是否都出现过,因此对单词集合里的元素是组合还是排序,并不在意,那么本题使用哪一种方法都可以。

        但本题存在特殊性,因为要求的是子串,所以最好是遍历背包放在外层循环,遍历物品放在内层循环。如果相反的话,需要将所有子串预先放在一个容器里,比较麻烦。

  2. 代码

    class Solution {
    public:
        bool wordBreak(string s, vector<string>& wordDict) {
            int n = s.size();
            unordered_set<string> WordSet(wordDict.begin(), wordDict.end());
            vector<bool> dp(n+1, false);
            dp[0] = true; // 初始状态
            for(int i=1; i<=n; ++i){
                for(int j=0; j<=i; ++j){
                    string word = s.substr(j, i-j); // (起始位置,长度)
                    if(WordSet.find(word) != WordSet.end() && dp[j]){
                        dp[i] = true;
                    }
                }
            }
            return dp[n];
        }
    };
    
  3. 收获

    • 总感觉之前做过类似的题,不过不是使用动态规划的解法。这道题完全没思路,找了很多题解才明白,最后参考的是代码随想录的解法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值