单词拆分----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

相关推荐
小欣加油6 小时前
leetcode56 合并区间
c++·算法·leetcode·职场和发展
lqqjuly6 小时前
前沿算法深度解析(二)
人工智能·算法·机器学习
徐小夕7 小时前
万字长文!千万级文档 RAG 知识库系统落地实践
前端·算法·github
akunkuntaimei7 小时前
2026年高考数学各省真题及答案(完整版)
算法·高考
Hello:CodeWorld8 小时前
C 风格变参 vs C++ 变参模板:核心区别与选型指南
c语言·c++·算法
8Qi89 小时前
LeetCode 516:最长回文子序列
算法·leetcode·职场和发展·动态规划
youngerwang10 小时前
【从搬运工到协处理器:网卡芯片架构、算法、验证与边缘演进深度剖析】
网络·算法·架构·芯片
KaMeidebaby11 小时前
卡梅德生物技术快报|纯化重组蛋白实操详解
人工智能·python·tcp/ip·算法·机器学习
手写码匠12 小时前
从零实现 Prompt 工程引擎:结构化提示、自动优化与多轮自省体系
人工智能·深度学习·算法·aigc
无限码力12 小时前
阿里算法岗 0530笔试真题 - 多约束条件下的元素匹配统计
算法·阿里笔试真题·阿里机试真题·阿里算法岗笔试