给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例 1:
输入: s = “barfoothefoobarman”, words = [“foo”,“bar”] 输出:[0,9] 解释:
从索引 0 和 9 开始的子串分别是 “barfoor” 和 “foobar” 。 输出的顺序不重要, [9,0] 也是有效答案。
示例2:
输入: s = “wordgoodgoodgoodbestword”, words =
[“word”,“good”,“best”,“word”] 输出:[]
这题的难度是困难。
我第一次做,想到的是暴力解法。即创造一个words的字典,对字符串进行遍历。截取一段分割后存入一个新字典,如果与原字典相同,说明全匹配,添加即可。说起来,不考虑字典花费的时间的话,时间复杂度应该是O(nm)。以下是代码
class Solution:
def make_list(self,s:str,n:int,word:dict)->bool:
i=0
joke={}
#print(s)
while(i<len(s)):
if s[i:i+n] not in word:
return False
if s[i:i+n] in joke:
joke[s[i:i+n]]+=1
else:
joke[s[i:i+n]]=1
i+=n
return joke==word
def findSubstring(self, s: str, words: List[str]) -> List[int]:
if len(words)==0:
return []
if not words[0]:
return [i for i in range(len(s)+1)]
word={}
joke=[]
for i in words:
if i in word:
word[i]+=1
else:
word[i]=1
len_of_word=len(words[0])
for left in range(len(s)):
right=left+len(words)*len_of_word
if self.make_list(s[left:right],len_of_word,word):
joke.append(left)
return joke
8000多ms,这就太丢脸了,一定有更好的办法。
改进了一下
这个主要就是对字典的使用进行了改进,不必每次从头开始添加,而是每次删去多余的我们不需要的数据。
class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
if len(words)==0:
return []
if not words[0]:
return [i for i in range(len(s)+1)]
word={}
ans=[]
for i in words:
if i in word:
word[i]+=1
else:
word[i]=1
lwd=len(words[0])#len_of_word
lwds=lwd*len(words)#len_of_words
for i in range(min(lwd,len(s)-lwds+1)):
left=wp=i#word_position
test={}
while(left+lwds<=len(s)):
w=s[wp:wp+lwd]
wp+=lwd
if w in word:
if w in test:
test[w]+=1
while(test[w]>word[w]):
test[s[left:left+lwd]]-=1
left+=lwd
else:
test[w]=1
else:
left=wp
test.clear()
if left+lwds==wp:
ans.append(left)
return ans
再贴一个方法跟我类似但是时间效率比我好的代码吧
执行用时为 64 ms 的范例
class Solution:
def findSubstring(self, s, words):
if len(words) == 0:
return []
lens = len(s)
lenw = len(words[0])
lenws = lenw * len(words)
if lens < lenws:
return []
counter = {}
for i in range(len(words)):
if words[i] in counter:
counter[words[i]] += 1
else:
counter[words[i]] = 1
res = []
for i in range(min(lenw, lens-lenws + 1)):
s_pos = word_pos = i
d = {}
while s_pos + lenws <= lens:
# 截取单词
word = s[word_pos:word_pos + lenw]
# 移动到下一个单词
word_pos += lenw
if word not in counter:
s_pos = word_pos
d.clear()
else:
if word not in d:
d[word] = 1
else:
d[word] += 1
while d[word] > counter[word]:
d[s[s_pos:s_pos + lenw]] -= 1
s_pos += lenw
if word_pos - s_pos == lenws:
res.append(s_pos)
return res