LeetCode139 - Word Break

本文探讨了如何使用动态规划解决字符串分割问题,通过实例详细解释了动态规划的应用,包括定义dp数组和状态转移方程,提供了C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

Note:

      · The same word in the dictionary may be reused multiple times in the segmentation.
      · You may assume the dictionary does not contain duplicate words.
Example 1:

       Input:              s = "leetcode", wordDict = ["leet", "code"]
      Output:            true
      Explanation:    Return true because "leetcode" can be segmented as "leet code".
Example 2:

       Input:              s = "applepenapple", wordDict = ["apple", "pen"]
       Output:            true
       Explanation:    Return true because "applepenapple" can be segmented as "apple pen apple".
             Note that you are allowed to reuse a dictionary word.
Example 3:

      Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
      Output: false

 

思路解析:

题目中给了两个已知量,一个是字符串s,另一个是含有字符串的数组——字典

判断字符串s   是否  可以由字典中的子串  组成

**************************************************************************** 初步分析

第一眼过后,思路混乱!!!因为字符串s可以由多个子串组成,也可以由单个或几个子串重复组成。即不断地遍历字符串s,并看字符串s的子区间是否存在于字典中;已遍历过的区间若存在于字典中,则记录,并遍历判断字符串s剩下的区间;若剩下的区间也存在于字典中,则正确。第一反应解决办法:

       1. 遍历字符串s,

       2. 找到第一个存在于字典中的子串区间

       3. 取出剩下的子串区间,并重复第1步

       4. 索引到end后,最后一个子串也存在于字典,则返回true

****************************************************************************** 动态规划

以上思路感觉不容易复现成代码,看了看别人的博客,用的是动态规划思想。!!! 这道题竟然也用动态规划思想,动态规划即当前状态可以由之前已计算出的状态得到。放在这个问题中就是当前位置处的子串是否可以由字典组成,取决于之前判断过的子串。

DP思想的难点在于:定义dp数组,找出状态转移方程

1. 定义dp数组

       这里用一个一维的数组 dp[i] 表示范围字符串s中 [0, i) 子串是否可以拆分(即是否由字典中单词组成) 

       dp数组的长度应为字符串 s.size()+1,因为dp[0]表示空字符情况,且为true

2. 状态转移方程

       用两层for循环,第一层是i,第二次是j。我们用 j 把 [0, i)范围内的子串 分为了两部分:[0, j) 子串和 [j, i) 子串。

       其中范围 [0, j) 就是dp[j],范围 [j, i) 就是s.substr(j, i-j)。其中 dp[j] 是之前已经判断过的状态,我们已经算出来了只需要在 字典中查找s.substr(j, i-j)是否存在了,如果二者均为true,将dp[i]赋为true。此时,即字符串s,[0, i)子串可以拆分,那么接着遍历,重复上面过程,直到遍历完整个字符串s。

        动态规划应用于此问题中,即需要得到字符串s此时的状态 dp[s.size] ———— [0, s.size)子串,即字符串s是否可以拆分,而dp[s.size]状态为动态规划问题中最后一个状态,应由之前的状态得到。而之前的某一状态dp[i],也是由再之前的状态dp[j]和判断s.substr(j, i-j)是否存在于字典后得到。如此一来,便清楚了。

 

代码实现:

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        // 动态规划思想
        // 1、建立动态数组 2、找出状态转移方程
        vector<bool> dp (s.size()+1, false);
        dp[0] = true;                           // 表示包含空字符子串
        for (int i = 0; i < dp.size(); i++) {
            for (int j = 0; j < i; j++) {
                if (dp[j] && find(wordDict.begin(), wordDict.end(), s.substr(j, i-j)) != wordDict.end()) {
                    dp[i] = 1;
                    break;
                }
            }
        }
        return dp.back();
    }
};

学习内容:

1. 再一次练习了动态规划,注意找出dp数组和状态转移方程。如何判断动态规划还是有待且很有待的提高。

2. 代码语言上,用了STL库里的find函数,用于查询数组

3. C++ substr用法:s.substr(pos, n),返回一个string,包含s中从pos开始的n个字符的拷贝(pos的默认值是0,n的默认值是s.size() - pos,即不加参数会默认拷贝整个s)

4. vector中的back(),表示容器的末尾的引用,即末尾的数。同样front()表示前端的引用。有别于begin()和end()是返回的迭代器,类似于指针。

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值