算法51:动态规划专练(力扣139题,单词拆分)---从左往右尝试模型的误区

题目:

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true

**注意:**不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 1:

复制代码
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。

示例 2:

复制代码
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
     注意,你可以重复使用字典中的单词。

示例 3:

复制代码
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false

这一题容易让人产生误导,一个target字符串,一个list数组,看起来非常像从左往右的尝试模型。一开始,我也是这么尝试的,按照从左往右尝试模型进行写递归版本代码的,写着写着发现不对劲。list数组中的单词可以重复使用,但是每个单词是固定的,不允许再拆分成逐个字母的。这一点和我之前写的贴纸拼词 算法34:贴纸拼词(力扣691题)-CSDN博客不一样

以下方为例:

输入: s = "catsandog", wordDict = "cats", "dog", "san", "cat" 输出: true

如果以cat开头,那么第二个单词为 sand,第三个单词为dog,可以拼出来

如果以cats开头,那第二个单词就为and,第三个单词就为og了 拼不出来。

因此,需要对s进行讨论和判断了。

|----|---|---|---|---|---|---|---|---|---|
| 字符 | c | a | t | s | a | n | d | o | g |
| 下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

  1. 如果以c、ca为单词,list里面找不到

2.如果以cat为单词,list里面能够找到;这就是1中情况;那么下标为3的s就可能是第二个单词的开头

3.如果以cats为单词,list里面也能够找到,那么下标为4的a就可能是第二个单词的开头;

  1. 如果第二个单词是以s开头的,san为单词,可以在list找到;此时,下标为6的d可能是下一个单词的开头了;

5.如果第二个单词是以a开头的,在list里面找不到;

  1. 第三个单词,则是以d开头,dog在list里面可以找到;因此,可以拼出最终的s字符串;

代码如何实现呢?

java 复制代码
package code04.动态规划专项训练03;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 力扣 139题 : 单词拆分
 * https://leetcode.cn/problems/word-break/description/?envType=study-plan-v2&envId=dynamic-programming
 *
 * 思路:
 * 1. 统计list中存在的无重复单词
 * 2. 字符串从0处开始往后找
 *     a. 如果字符串中能否切割出一个完整的单词,这个单词是在list表中出现的。那么就把这个单词末尾字符的下一个下标标记为新单词的开始位置,即dp表对应下标标记为true
 *     b. 如果找到末尾都找不到,就一直找。直到本轮递归结束
 * 3. 找到 dp 表中 对应为 true的下标。 从此下标开始可以组成一个新单词。具体逻辑与步骤2相同.
 *    举例说明:
 *    s = "catsandog"
 *    wordDict = ["cats", "dog", "sand", "and", "cat"]
 *
 *    字符串     c a t s a n d d o g
 *    dp表下标   0 1 2 3 4 5 6 7 8 9
 *    dp表下标   T F F T T F F T F F
 *    下标0处 为 true 一个字符串如果开头位置
 *    下标3处 为 true 因为cat在字典中能够找到,所以下标3可能是一个新单词的开头
 *    下标4处 为 true 因为cats在字典中能够找到,所以下标4可能是一个新单词的开头
 *    下标7处 为 true 无论是sand 还是 and 都是单词。因此他们末尾的下一个下标,即index=7可能是一个新单词的开头
 *
 * 4. 如果整个字符串都可以由字典list中单词拼接出来。那么这个字符串一定可以走到末尾。而dp表的长度是比字符串的长多多1. 即dp
 *    表的末尾肯定为true。
 */
public class WordBreak_官方题解_02 {

    public boolean wordBreak(String s, List<String> wordDict)
    {
        //统计list中无重复单词
        Set<String> wordDictSet = new HashSet(wordDict);

        //记录哪些位置可以是单词的开始位置
        boolean[] dp = new boolean[s.length() + 1];
        
        //默认从下标为0处为单词的开始位置
        dp[0] = true;
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 0; j < i; j++) {
                //dp[j] = true, 代表j这个位置是一个单词的开头
                if (dp[j] && wordDictSet.contains(s.substring(j, i))) {
                    //i代表本来循环的末尾位置。因此 String.substring(j, i) 是 [j,i)
                    //i的前一个位置为单词的末尾位置。那么i就是新单词的开始位置或者空的占位
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }

    public static void main(String[] args) {
        WordBreak_官方题解_02 s = new WordBreak_官方题解_02();

        String a = "leetcode";
        List<String> list2 = new ArrayList<>();
        list2.add("leet");
        list2.add("code");
        System.out.println(s.wordBreak(a, list2));

       /* List<String> list = new ArrayList<>();
        list.add("cats");
        list.add("dog");
        list.add("sand");
        list.add("and");
        list.add("cat");

        String s1 = "catsandog";
        System.out.println(s.wordBreak(s1, list));*/
    }
}

这一题倒不难,只是由于我之前习惯性的按照动态规划的固定模板化思路去解题,容易进入误区;

老是想着套路、模型去解题,有时候确实事半功倍;但是,这一题却反其道而行,让你看着像是之前的解题套路,结果就迷茫了。

下一题,我将分享另一个看着像从左往右模型套路的题。但是,由于数据量比较大,肯定要排除掉从左往右模型的题目。

相关推荐
江畔柳前堤5 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore6 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考8 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX8 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面9 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号9 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽9 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI9 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者11 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者11 小时前
【征程6】校准量化中HistogramObserver解析
算法