LeetCode 30. 串联所有单词的子串
题目:
给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例 1:
输入:
s = "barfoothefoobarman",
words = ["foo","bar"]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。
示例 2:
输入:
s = "wordgoodgoodgoodbestword",
words = ["word","good","best","word"]
输出:[]
思路:
脑子不灵光,可以想出滑动的指针方法, 但是写不出来...
暴力搜索是我最后的倔强~~~~
方法一:
暴力搜索~~~
以words中一个str的长度(题目条件是每个元素长度都相同),进行查找。因为不用考虑顺序,所以只要从s中截取的部分包含在words(因为是匹配该列表,每次都循环都需要该对象,所以用切片来copy复制,找到就可以remove掉,没有就不符合条件跳出,当列表长度为0的时候,index即符合条件。
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
if len(words)==0 or len(s)==0:
return []
wl=len(words[0])
ss=[]
for i in range(len(s)-wl*len(words)+1):
tw=words[:] #需要用切片深copy匹配串
k=i
while len(tw)!=0:
if s[k:k+wl] in tw: #当等间距长度检索的字符包含在匹配串中 ,就remove
tw.remove(s[k:k+wl])
k+=wl
else:
break
if len(tw)==0: #长度为0即为符合条件的index,塞入数组
ss.append(i)
return ss
方法二:
摘自题解summer_tree ,思路很清晰~我也有想到双指针移动,但是写不出~~苦恼😖
1、首先这个题里, words里的子串长度都相等,则这个题类似76题,可以把words看成一个字符串,里面的每个word 看成一个字母,
2、words=["foo","bar"] 即 words="AB", 则 s="barfoothefoobarman" => "BAXABY",
3、就转换成了 给个字符串s ,模式串t, 求包含模式串字符的子串
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
import collections
if not s or not words:
return []
words_dict = collections.Counter(words)
one_word_len = len(words[0])
n = len(s)
if n < one_word_len:
return []
window_cnt = 0
cur_window_dict = collections.Counter()
ret = []
for i in range(one_word_len):
left = right = i
cur_window_dict.clear()
while right + one_word_len <= n:
#从s中取一个word长度的串
c = s[right: right + one_word_len]
right += one_word_len
#如果没有在模式串中 直接清空map, left 前进到 right位置
if c not in words_dict:
left = right
cur_window_dict.clear()
window_cnt = 0
else:
cur_window_dict[c] += 1
window_cnt += 1
#缩小窗口
while cur_window_dict[c] > words_dict[c]:
d = s[left: left + one_word_len]
cur_window_dict[d] -= 1
left += one_word_len
#直接判断两个counter 是否相等
if cur_window_dict == words_dict:
ret.append(left)
return ret
或者是这样:
出自作者:HardCandy,讲解的也蛮细致的,从最直接的单个字符去搜索,到变成以字符长度,最后到优化过滤不符合条件的case。
很直观的了解这题目的思路~
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
if not words:
return []
w_len, s_len = len(words[0]), len(s)
t_len = w_len * len(words) # 子串的长度
word_dict = {} # words的哈希表
for word in words:
word_dict[word] = word_dict.get(word, 0) + 1 #统计word中每个字符的次数
ans = []
for offset in range(w_len):
lo, lo_max = offset, s_len - t_len
while lo <= lo_max:
tmp_dict = word_dict.copy()
match = True
for hi in range(lo + t_len, lo, -w_len): # 从尾到头搜索单词
word = s[hi - w_len: hi]
if word not in tmp_dict or tmp_dict.get(word, 0) == 0:
match = False
break # 当前单词不符合要求 直接停止这个子串的搜索
tmp_dict[word] -= 1
if match:
ans.append(lo)
lo = hi # 对lo直接赋值
return ans
Knowledge, like candlelight, can illuminate a person and countless people.