单词拆分----dp

思路:

刚开始看的时候没有思路,但我看给的样例,可以多次遍历wordDict看。。。好像不太对准备看看题解。

首先需要知道这道题的dp的公式代表这什么,dpi表示 字符串s从起始位置到位置i,能否被被拆分成字典中的单词(可能是一个,也可能是多个)。

比如dp3就是问s1,s2,s3 这三个字符能否拆分成字典中单词的组合。

于是我们下一步需要思考一下代码应该怎么写:

复制代码
class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> wset = new HashSet<>(wordDict);
        int n = s.length();
        boolean[] dp = new boolean[n + 1];
        dp[0] = true; // 空字符串可以拼出来

        for(int i = 1;i <= n;i++){
            for(int j = 0;j < i;j++){
            if(dp[j] && wset.contains(s.substring(j,i))){
                dp[i] = true;
            }
            }
        }

        return dp[n];
    }
}

s.substring(a,b)中b是不包含的也就是说真实包含的数组下标是,a-----b-1

解释一下dp0为什么等于true,因为在拆分的时候

s = "leetcode"wordDict = ["leetcode"]

  • i = 8,内层循环 j = 0

    • dp[0]true,并且 s.substring(0, 8) = "leetcode" 在字典中 → 条件成立,dp[8]=true

如果没有 dp[0]=true,那么即使整个字符串是一个单词,也无法通过 j=0 的情况识别出来,所有以 j=0 开头的判断都会失败,导致错误结果。

我们一步一步把 if (dp[j] && wordSet.contains(s.substring(j, i)))dp[i] = true 之间的逻辑关系拆开讲清楚。


1. 先明确 dp 数组的含义

在这段代码中:

  • dp[k] 表示:原字符串 s 的前 k 个字符 (即 s[0]s[k-1] 这一段)能否被拆分成字典中的单词

  • 例如 dp[3] 就是问 s[0],s[1],s[2] 这三个字符能否拆分成字典里的单词组合。


2. 我们要算什么?

外层循环 i 从 1 到 n,是要依次判断 dp[1], dp[2], ... dp[n] 是否为真。

当我们在计算 dp[i] 时,我们要问:i 个字符能不能被拆分成字典里的单词?

一种思考方式是:把前 i 个字符想象成 "前面一段" + "最后一段"

  • "前面一段"的长度是 j(0 ≤ j < i),也就是 s[0..j-1]

  • "最后一段"就是从索引 ji-1 的子串,长度为 i-j,也就是 s.substring(j, i)

如果能找到某个 j,使得:

  • 前面一段 (s[0..j-1]) 可以被拆分成字典单词(即 dp[j] == true),并且

  • 最后一段 (s.substring(j, i)) 本身就在字典里(wordSet.contains(...)),

那么整个 s[0..i-1] 就肯定可以被拆分(前面一段按 dp[j] 的方式拆,最后一段直接作为单词)。


3. 所以 if 条件里的 dp[j] && wordSet.contains(...) 就是检查这个假设是否成立

  • dp[j] == true → 前 j 个字符可拆分。

  • s.substring(j, i) 在字典里 → 从 ji-1 这一段直接是一个单词。

如果两者都满足,那么 s[0..i-1] 就找到了一个拆分方案,因此 dp[i] 应该为 true


4. 为什么 dp[i] = true 只写一次就够了?

因为一旦我们找到了一个有效的 j,就证明了 dp[i] 可以为 true,不需要继续找其他 j(反正结果已经是真了)。所以代码里 break 跳出内层循环。


5. 举个例子(用具体数字帮助理解)

s = "leetcode"wordDict = ["leet","code"]

  • 我们要算 dp[8](整个字符串长度 8)。

  • 内层循环 j 从 0 到 7:

    • j = 4 时:

      • dp[4] 是什么?前面算过,"leet" 可拆分 → dp[4]=true

      • s.substring(4, 8) 是什么?索引 4~7 → "code",在字典中。

    • 条件成立 → 给 dp[8] = true

这就是 "前 8 个字符可以拆成 (前4个字符:leet) + (4..8:code)"。


总结一句话:

if (dp[j] && wordSet.contains(s.substring(j, i))) 就是在问:"能不能把前 i 个字符切成两半,使得前半部分可拆分(dp[j]=true),后半部分本身就是一个单词(在字典里)? "

如果能,那么 dp[i] 就是 true

相关推荐
烬羽2 小时前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
先吃饱再说17 小时前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰20 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术21 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六1 天前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术1 天前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize1 天前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考2 天前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
美团技术团队2 天前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法