30. 串联所有单词的子串
题目-困难难度
给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。
s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。
例如,如果 words = [“ab”,“cd”,“ef”], 那么 “abcdef”, “abefcd”,“cdabef”, “cdefab”,“efabcd”, 和 “efcdab” 都是串联子串。 “acdbef” 不是串联子串,因为他不是任何 words 排列的连接。
返回所有串联子串在 s 中的开始索引。你可以以 任意顺序 返回答案。
示例 1:
输入:s = “barfoothefoobarman”, words = [“foo”,“bar”]
输出:[0,9]
解释:因为 words.length == 2 同时 words[i].length == 3,连接的子字符串的长度必须为 6。
子串 “barfoo” 开始位置是 0。它是 words 中以 [“bar”,“foo”] 顺序排列的连接。
子串 “foobar” 开始位置是 9。它是 words 中以 [“foo”,“bar”] 顺序排列的连接。
输出顺序无关紧要。返回 [9,0] 也是可以的。
示例 2:
输入:s = “wordgoodgoodgoodbestword”, words = [“word”,“good”,“best”,“word”]
输出:[]
解释:因为 words.length == 4 并且 words[i].length == 4,所以串联子串的长度必须为 16。
s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接。
所以我们返回一个空数组。
示例 3:
输入:s = “barfoofoobarthefoobarman”, words = [“bar”,“foo”,“the”]
输出:[6,9,12]
解释:因为 words.length == 3 并且 words[i].length == 3,所以串联子串的长度必须为 9。
子串 “foobarthe” 开始位置是 6。它是 words 中以 [“foo”,“bar”,“the”] 顺序排列的连接。
子串 “barthefoo” 开始位置是 9。它是 words 中以 [“bar”,“the”,“foo”] 顺序排列的连接。
子串 “thefoobar” 开始位置是 12。它是 words 中以 [“the”,“foo”,“bar”] 顺序排列的连接。
提示:
- 1 <= s.length <= 104
- 1 <= words.length <= 5000
- 1 <= words[i].length <= 30
- words[i] 和 s 由小写英文字母组成
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/substring-with-concatenation-of-all-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
1. 优化遍历方式
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
# 获取长度
lw,lww = len(words),len(words[0])
# 定义窗口右边界
r = lw*lww
ls = len(s)
res = []
# 遍历
for i in range(ls-r+lww):
#获取单词字符串
word = s[i:i+r]
# 获取单词列表
li = []
for j in range(0,len(word),lww):
li.append(word[j:j+lww])
if Counter(li)==Counter(words):
res.append(i)
return res
2. 字典对比
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
# 获取长度
lw,lww = len(words),len(words[0])
# 定义窗口右边界
r = lw*lww
ls = len(s)
dic = defaultdict(int)
for i in words:
dic[i] += 1
res = []
# 遍历所有可能组合
for i in range(ls-r+lww):
# 与 words内所有单词字数总和相同的字符串
w = s[i:i+r]
# 如果匹配,就把每个单词放入li内,和words进行对比
d = defaultdict(int)
for j in range(0,r,lww):
d[w[j:j+lww]]+=1
# 当d与dic相同,加入当前i到res
if d == dic:
res.append(i)
return res
3. 字典抵消
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
# 获取长度
lw,lww = len(words),len(words[0])
# 定义窗口右边界
r = lw*lww
ls = len(s)
dic = defaultdict(int)
for i in words:
dic[i] += 1
res = []
# 遍历所有可能组合
for i in range(ls-r+lww):
# 如果匹配,就把每个单词放入li内,和words进行对比
d = dic.copy()
flag = True
for j in range(i,i+r,lww):
d[s[j:j+lww]]-=1
if d[s[j:j+lww]] < 0:
flag = False
break
# 当d与dic相同,加入当前i到res
if flag == True:
res.append(i)
return res
4. 设置等宽的窗口右移 + 列表对比(超时)
超出时间限制
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
# 获取长度
lw,lww = len(words),len(words[0])
# 定义窗口右边界
r = lw*lww
res = []
# 遍历
for i in range(0,len(s)):
#获取单词字符串
word = s[i:i+r]
# 获取单词列表
li = []
for j in range(0,len(word),lww):
li.append(word[j:j+lww])
if Counter(li)==Counter(words):
res.append(i)
return res