题目:
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
这题我一开始用暴力的回溯解法,因为忘记记录已搜索过的拆分点,导致在极端数据下会超时,时间复杂度会到O(n^n),如下:
因此,改用题解中的第一种解法记忆化回溯,也就是用一个列表记录已经访问过的拆分点,代表从[x,n)是否true,这样就能将时间复杂度转化为O(n^2),代码如下:
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
n = len(s)
if n == 0 or (n == 1 and s in wordDict):
return True
if n == 1:
return False
dic = {}
for word in wordDict:
p = s.find(word)
while p != -1:
if p not in dic.keys():
dic[p] = []
dic[p].append(p+len(word))
p = s.find(word, p+1)
visited = [False for _ in range(n)]
ans = [False for _ in range(n)]
def findBreak(x):
if x == n:
return True
if visited[x]:
return ans[x]
if x not in dic.keys():
visited[x] = True
return False
for y in dic[x]:
ans[x] = findBreak(y)
if ans[x]:
break
visited[x] = True
return ans[x]
return findBreak(0)
另外,题解还介绍了两种跟记忆化回溯时间空间复杂度相似的解法
① 宽度优先搜索,在s前后假定一个begin和end,然后不断从字典里搜索符合与当前子串开头相同且能匹配的单词;
② 动态规划:思想还是通过dp[x]记录[0,x)是否能够满足条件,然后用状态转移方程解决。