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

  • "最后一段"就是从索引 j 到 i-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) 在字典里 → 从 j 到 i-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。

相关推荐
垆边人似月.39 分钟前
华为机试题 :字符串压缩
算法·华为
ggb喔40 分钟前
52pojie 的图片工具:为什么无损转换后体积涨了 6 倍、照片方向还是歪的
图像处理·python·算法·计算机视觉·图形渲染·媒体
菜鸟~noob23343 分钟前
【电子战】第25篇:自由空间、双射线与菲涅尔区【含matlab代码】
开发语言·算法·matlab
地平线开发者1 小时前
地平线征程6M YOLOv8s 部署
算法·自动驾驶
Run_Teenage1 小时前
算法:Manacher(马拉车)算法、中心扩展算法
算法
Tisfy2 小时前
LeetCode 0301.删除无效的括号:二进制枚举 / 回溯
算法·leetcode·字符串·题解·回溯·括号匹配·二进制枚举
Nil2082 小时前
leetcode 322零钱兑换
算法·leetcode·职场和发展
海绵宝宝转agent2 小时前
2026-10-9 leetcode100刷题+面经整理
笔记·算法·面试
yi0112 小时前
DAY24: LeetCode 167:两数之和 II|从暴力枚举到左右双指针
笔记·python·算法·leetcode·二分查找·双指针
木井巳2 小时前
【BFS 解决拓扑排序】课程表
java·算法·leetcode·广度优先·宽度优先·推荐算法·图搜索算法