题目描述
思路解析动画文字版
每个位置都能切,后缀会被反复判断。DP 把“前缀能否拆”记下来。
如果存在一个切点 j,左边 s[0:j] 能拆,右边 s[j:i] 是词,那么 dp[i] 为 true。
初始化:空串可以被拆成 0 个词,所以 dp[0]=true。
检查 leet:到 i=4 时,切点 j=0:dp[0]=true,s[0:4]=leet 在词典里。
中间位置失败:到 i=5、6、7,找不到一个合法切点,所以保持 false。
检查 code:到 i=8,切点 j=4:dp[4]=true,s[4:8]=code 在词典里。
答案看 dp[n]:最后 dp[8]=true,说明整个字符串可以拆完。
反例 catsandog:如果最后一个位置始终找不到合法切点,dp[n] 就是 false。
切点 j 是这题的核心变量。
边界三连:空串、多切法、末尾失败,是 word break 的关键边界。
雷区实演 · 贪心拿最长会错(s="aaaa", dict=["aaa","aa"]):贪心「每次拿最长」会在 "aaa" 后被单个 "a" 卡死、误判无解;DP 枚举所有分割点,找到 aa+aa → true。这就是必须用 DP、不能贪心的原因。
面试追问 1:LC140,需要 DFS + 记忆化,记录从每个位置出发的所有句子。
面试追问 2:可以用最大词长限制 j 的范围,或用 Trie 辅助匹配。
面试追问 3:它代表“什么都不选”的合法起点,方便第一个词转移。
这题学完不要乱跳,下一步去 对应专题 连刷同类题;卡住时用 AI 答疑追问“为什么这一步成立”,比只背答案更稳。
参考代码
class Solution: def wordBreak(self, s, wordDict): words = set(wordDict) dp = [False] * (len(s) + 1) dp[0] = True for i in range(1, len(s) + 1): for j in range(i): if dp[j] and s[j:i] in words: dp[i] = True break return dp[-1]复杂度
- 时间复杂度:O(n³),枚举分割点 O(n²),每次取子串+查词典,子串最长 O(n),故最坏 O(n³)
- 空间复杂度:O(n + dict),dp 数组和词典 set
可套用的代码模板
这一步不是复读 单词拆分 的参考答案,而是抽出这题真正能迁移的骨架;换题时先判断状态/容器含义,再填核心分支。
# 1. 说清 dp[状态] 的含义dp = 初始值for state in 遍历顺序: for choice in 可选动作: candidate = dp[前置状态] + 这次选择的代价 dp[state] = best(dp[state], candidate)return dp[答案状态]易错点
面试追问把动画讲成自己的话
追问如何返回所有拆分句子?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
最长递增子序列
LeetCode 300 · 中等 · 沿着 一维动态规划 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题