[LeetCode]30 串联所有单词的子串

题目描述

给定一个字符串 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"]
输出:[]

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution:
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
if len(words) == 0:
return []

str_len = len(s)
len_word = len(words[0])
total_len = len_word * len(words)
if str_len < total_len:
return []

words_dic = {}
for word in words:
words_dic[word] = words_dic.get(word, 0) + 1

result = []
for str_start in range(min(len_word, str_len - total_len + 1)):
head = str_start
tail = head + len_word
scan_dic = {}
while tail <= str_len:
cur_word = s[tail - len_word:tail]
if cur_word in words_dic:
scan_dic[cur_word] = scan_dic.get(cur_word, 0) + 1
while scan_dic[cur_word] > words_dic[cur_word]:
scan_dic[s[head:head + len_word]] -= 1
head += len_word
if tail - head == total_len:
result.append(head)
scan_dic[s[head:head + len_word]] -= 1
head += len_word
else:
scan_dic.clear()
head = tail
tail += len_word

return result