DP专题17 单词拆分

文章讲述了如何使用动态规划解决LeetCode中的字符串拼接问题,将问题转化为完全背包问题,并结合排列数遍历,通过dp数组判断给定字符串S能否由字符串数组中的部分字符串拼接而成。
摘要由CSDN通过智能技术生成

本题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目:

思路:

        由题意,根据题目意思,给出字符串 S,以及一个字符串数组,问字符串数组中  s_{_{i}}  是否可以任取字符串拼成字符串 S。

        根据这个题目,我们可以看成完全背包问题,又因为我们选取的字符串 s_{_{i}} 可以不在乎顺序的进行选取,所以我们用 排列数的遍历方式,总结下来:  完全背包问题+排列数遍历方式

        第一步,确定dp[i] 的含义。

        这里题目要求的是判断是否可以拼成字符串 S,

        所以我们 dp 数组可以为 bool 类型的dp数组,

        当 dp [ 结果含义下标 ] 返回真就是真,返回假就是假

        其中 dp[ i ] 下标  i 的含义我们得要确定好。

        我们根据正常思维去联想   提取的字符串S 的片段   的进行判断是否存在我们的字符串数组,

其中提取字符串 S 的片段的时候,有一个因素就是 片段 S 的长度。

        所以我们可以将 dp[ i ] 下标  i 的含义定义为 字符串长度。

        当 我们 dp[ S.lenght() ] = true 的时候就是有真结果,反之。

        综上所述,我们确定好了 dp[ i ] 的全部含义了.

        dp[ i ]  为 我们求是否 可以拼成 S 的结果,   i  为 字符串长度

        第二步,确定 dp公式

        根据总结下来:  完全背包问题+排列数遍历方式

        这里   背包容量,我们可以是  S 的长度,问 '物品' 字符串选取S片段 是否符合,并且长度可以凑成 背包容量 ,既可以。

        详细遍历过程如下:

                

// 排列数遍历,先遍历背包容量,再遍历物品
for(int i = 1;i <= S.size();++i)    // S 目标拼凑成的字符串长度
{
    for(int j = 0;j < i;++j)    // 选取物品片段长度
    {
         string word = s.substr(j,i - j);    // 这里是选取字符串片段

    }
}

        确定好 dp 整个过程后,逻辑也开始清晰起来,当 我们截取的 S 字符串片段存在的时候,并且我们之前凑成的 dp[ j ] 也存在的时候,说明 当前 i 是可以凑成的。

        dp 公式如下:   dp[ i ] = bool (wordDict.find(word) == true and dp[ j ]); 

        这里可能有点疑惑,为什么要 dp [ j ] 判断,解释如下:

        

第三步,确定dp 初始化

        由 第二步 我们整个  dp  已经得到清晰的逻辑了,我们是根据 截取的字符串长度进行拼凑递推下去,直到得到结果。其中遍历顺序有个特点,就是  我们遍历字符串 S 长度的时候为什么 不是 

for(int i = 0;i <= s.size();++i)

这里就是我们 dp 初始化的关键, 我们就是  dp[ 0 ] = true  的初始化

我们为什么要 dp[ 0 ] = true 的初始化,就是因为 我们可以将 空字符串 也当作是截取的一个片段,我们空串是肯定存在的,视作为可以拼凑成的, 其它的我们得需要根据 wordDict 的存在情况进行实际的拼凑。 所以  dp[ 0 ] = true ,其它为 false

代码详解如下:

class Solution {
public:
    unordered_set<string>st; // 用于查新判断截取字符串存在情况
    bool wordBreak(string& s, vector<string>& wordDict) {
        for(string &i:wordDict) st.emplace(i);   // 提前哈希存储好我们 wordDict 存在哪些 字符串
        int len = s.size(); // 计算字符串长度
        vector<bool>dp(len + 2,false);  // 定义 截取长度字符串 dp  bool数组
        dp[0] = true;   // dp 初始化,空字符串是 true
        
        // 开始完全背包,排列数遍历法遍历 dp
        for(int i = 1;i <= len;++i) // '背包' S 字符串长度
        {
            if(dp[i]) continue;    // 小优化
            for(int j = 0;j < i;++j)    // 截取字符串的 下标
            {
                if(!dp[j]) continue;    // 小优化
                string word = s.substr(j,i - j);    // 截取字符串
                if(st.find(word) != st.end() and dp[j]) dp[i] = true; // dp 公式
            }
        }
        return dp[len]; // 返回结果
    }
};

最后提交:

  • 13
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值