@@ -44,17 +44,38 @@ https://leetcode-cn.com/problems/word-break/
4444
4545这道题是给定一个字典和一个句子,判断该句子是否可以由字典里面的单词组出来,一个单词可以用多次。
4646
47- 暴力的方法是无解的,复杂度极其高。 我们考虑其是否可以拆分为小问题来解决。
48- 对于问题` (s, wordDict) ` 我们是否可以用(s', wordDict) 来解决。 其中 s' 是 s 的子序列,
49- 当 s'变成寻常(长度为 0)的时候问题就解决了。 我们状态转移方程变成了这道题的难点。
47+ 暴力的方法是无解的,复杂度比较高,但是可以通过。
5048
51- 我们可以建立一个数组 dp, dp[ i] 代表 字符串 s.substring(0, i) 能否由字典里面的单词组成,经过这样的抽象我们就可以建立 dp[ i - word.length] 和 dp[ i] 的关系。它们有什么关系?又该如何转移呢?
49+ 暴力思路是从匹配位置 0 开始匹配, 在 wordDict 中一个个找,如果其能和 s 匹配上就尝试进行匹配,并更新匹配位置。
50+
51+ 比如 s = "leetcode", wordDict = [ "leet", "code"] 。
52+
53+ 那么:
54+
55+ - 先试试 leet 可以匹配么?可以的,匹配后 s 剩下 code,继续在 wordDict 中找。
56+ - leet 可以匹配么?不能!code 能够匹配么?可以!返回 true 结束
57+
58+ 如果 wordDict 遍历一次没有任何进展,那么直接返回 false。
59+
60+ 注意到如果匹配成功一次后,本质是把问题规模缩小了,问题性质不变,因此可以使用动态规划来解决。
61+
62+ ``` py
63+ @cache
64+ def dp (pos ):
65+ if pos == len (s): return True
66+ for word in wordDict:
67+ if s[pos:pos+ len (word)] == word and dp(pos + len (word)): return True
68+ return False
69+ return dp(0 )
70+ ```
71+
72+ 复杂度为 $O(n^2 * m)$ 其中 n 为 s 长度, m 为 wordDict 长度。
5273
5374我们用图来感受一下:
5475
5576![ 139.word-break-1] ( https://p.ipic.vip/5b21ws.jpg )
5677
57- 没有明白也没有关系,我们分步骤解读一下 :
78+ 接下来我们以题目给的例子分步骤解读一下 :
5879
5980(以下的图左边都代表 s,右边都是 dict,灰色代表没有处理的字符,绿色代表匹配成功,红色代表匹配失败)
6081
@@ -71,9 +92,28 @@ https://leetcode-cn.com/problems/word-break/
7192
7293![ 139.word-break-6] ( https://p.ipic.vip/yu4j2f.jpg )
7394
95+ 我们可以进一步优化, 使得复杂度和 m 无关。优化的关键是在 dp 函数内部枚举匹配的长度 k。这样我们截取 s[ pos: pos +k] 其中 pos 表示当前匹配到的位置。然后只要看 s[ pos: pos +k] 在 wordDict 存在与否就行。存在了就更新匹配位置继续,不存在就继续。而* 看 s[ pos: pos +k] 在 wordDict 存在与否就行* 是可以通过将 wordDict 中放入哈希集合中进行优化的,时间复杂度 O(1),牺牲一点空间,空间复杂度 O(m)
96+
7497## 代码
7598
76- 代码支持: JS,CPP
99+ 代码支持: Python3, JS,CPP
100+
101+ Python3 Code:
102+
103+ ``` py
104+ class Solution :
105+ def wordBreak (self , s : str , wordDict : List[str ]) -> bool :
106+ wordDict = set (wordDict)
107+ @cache
108+ def dp (pos ):
109+ if pos == len (s): return True
110+ cur = ' '
111+ for nxt in range (pos, len (s)):
112+ cur += s[nxt]
113+ if cur in wordDict and dp(nxt + 1 ): return True
114+ return False
115+ return dp(0 )
116+ ```
77117
78118JS Code:
79119
@@ -123,10 +163,10 @@ public:
123163
124164**复杂度分析**
125165
126- 令 S 和 W 分别为字符串和字典的长度。
166+ 令 n 和 m 分别为字符串和字典的长度。
127167
128- - 时间复杂度:$O(S ^ 3 )$
129- - 空间复杂度:$O(S + W )$
168+ - 时间复杂度:$O(n ^ 2 )$
169+ - 空间复杂度:$O(m )$
130170
131171大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。
132172大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
0 commit comments