lc 140. Word Break II
https://leetcode.com/problems/word-break-ii/
给你一个words的set()以及一个字符串,返回所有的断句方式
Input: s = "catsanddog
" wordDict =["cat", "cats", "and", "sand", "dog"]
Output:[ "cats and dog", "cat sand dog" ]
单词就是梯子,目的是用各种梯子搭到最后,输出所有的梯子搭建可能性。
⚠️注意:题目需要的东西不同,策略不同,需要返回所有解和只返回能否有明显不同。
方法1:
每个点上都保存所有都当前点的解法,然后可以按照后面的匹配继续扩展。
空间复杂度很高,但是时间复杂度是一样的,思路比较简单,但是有个最大的问题,就是在没有解的时候,时间复杂度仍然为指数级别的。因为后面是否会匹配失败我们不管,我们只管一味向前。所以,如果先有个高效的方法判断有解没解,那么我们这个方法在时间上不会吃亏,就是内存开销大。
方法2:
每个点保存能由哪个词到达于此,为什么是记录在结尾位置而不是开始位置呢,自己想一下。
或者两头往中间找,防止爆炸,这个就有点厉害了,以后再实现吧。。
因为我们从左往右寻找,是找到了一棵向右发展的有向无环图,仅仅有一部分才会通向最终位置,所以我们寻找时从左往右,然后在返回答案时从右往左,于是乎不就是时间复杂度严格正比于答案数量了吗,这样不会有任何的额外错误分支开销。
保存了哪个词到达于此之后,就是一个典型的递归遍历了。
方法3:
class Solution:
def wordBreak(self, s, wordDict):
memo = {len(s): ['']} #很灵性
def sentences(i):
if i not in memo:
memo[i] = [s[i:j] + (tail and ' ' + tail)
for j in range(i+1, len(s)+1)
if s[i:j] in wordDict
for tail in sentences(j)]
return memo[i]
return sentences(0)
好好看看那个超长的list生成,很灵性!
这个方法不光炫技了,也是最最省时的操作了可以说,当然,可以把list转成set,这样在查找时可以加速成O(1)的速度。学代码,学思想。
即是dp又是深搜。
现在有一个问题,就是它没有想方法2一样提前判断可行性就指数增加地往前找了,为什么在某些最终无解的情况下时间没有炸掉?
方法1是广搜,方法3是深搜。方法1不管是否有用都有list的扩张动作。但是看看方法3,一直在从后面的for tail in sentences(j)中取东西,如果没有解是取不出来的。这就保证了,虽然遍历从一端到另一端的所有可能,但是却仅仅在有解的情况下才有list增长操作。实属666的六学精品,两开花。
好好想想深搜和广搜的异同,有很多的发现~在这端的深搜是不是另一端的广搜呢?是又不是。
Trick:两个方法不管哪个,都要检查一下当前的位置能否到达,如果没有方式能走到当前位置,那么就不要找
笨蛋方法1:
dpr = [[] for i in range(len(s) + 1)]
dpr[0].append([])
def myFrom(i):
for aw, w in enumerate(wordDict):
if s[i:].startswith(w):
dpr[i + len(w)] += [p + [aw] for p in dpr[i]]
for i in range(len(s)):
if len(dpr[i])>0:
myFrom(i)
for i in range(len(dpr[-1])):
p = dpr[-1][i]
p = [wordDict[j] for j in p]
dpr[-1][i] = ' '.join(p)
return dpr[-1]
机智方法2:
dpr = [[] for i in range(len(s) + 1)]
def myFrom(i):
# ans=[]
for aw in range(len(wordDict)):
w = wordDict[aw]
if s[i:].startswith(w):
dpr[i + len(w)].append(aw)
myFrom(0)
for i in range(1, len(s)):
if len(dpr[i]) > 0:
myFrom(i)
if len(dpr[len(s)]) == 0:
return []
anss = []
tem = []
def pri(i, a):
if i == 0:
s = ''
k = len(a) - 1
while k > 0:
s += wordDict[a[k]]
s += ' '
k -= 1
s += wordDict[a[0]]
anss.append(s)
for j in dpr[i]:
a.append(j)
pri(i - len(wordDict[j]), a)
del a[-1]
pri(len(s), tem)
return anss