Word Break I / II
这个题型 / 算法点的总结
这组题的关键是区分“判断能不能拆”和“输出所有拆法”:
Word Break I更像 DPWord Break II更像 DFS + memo
题目含义
这一组题经常一起出现:
Word Break I:判断字符串能不能被字典拆开Word Break II:返回所有合法拆分方案
第一题偏 DP,第二题偏 DFS + memo。
Word Break I
Python 代码
from typing import List
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
word_set = 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 word_set:
dp[i] = True
break
return dp[-1]
时间复杂度
通常写 O(n^2)。
空间复杂度
O(n)。
怎么想到这个方法
题目问“前缀能不能被拆开”,最自然的状态就是:
dp[i]表示前i个字符是否可拆分
示例 case
- 输入:
s = "leetcode",wordDict = ["leet", "code"] - 输出:
True - 为什么:前缀
leet可拆,剩余code也可拆
Word Break II
Python 代码
from functools import lru_cache
from typing import List
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
word_set = set(wordDict)
@lru_cache(None)
def dfs(start: int) -> List[str]:
if start == len(s):
return [""]
ans = []
for end in range(start + 1, len(s) + 1):
word = s[start:end]
if word not in word_set:
continue
for tail in dfs(end):
ans.append(word if not tail else word + " " + tail)
return ans
return dfs(0)
时间复杂度
最坏指数级,但 memo 会显著减少重复搜索。
空间复杂度
O(n + 输出规模)。
怎么想到这个方法
第二题不是只判断真假,而是要输出所有方案,所以纯 DP 不够顺手。最自然的做法是:
- DFS 枚举切分点
memo记住某个起点后面的所有答案
示例 case
- 输入:
s = "catsanddog",wordDict = ["cat","cats","and","sand","dog"] - 输出:
["cat sand dog", "cats and dog"] - 为什么:从同一个起点往后可能有多种合法切分,所以需要返回全部方案
常见 Follow-up
- 如何先用
Word Break I作为剪枝? - 如果 interviewer 问更快,能不能讲
Trie + memo? - 为什么
Word Break II不做 memo 会很慢?