題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/substring-with-concatenation-of-all-wordspython
給定一個字符串 s 和一些長度相同的單詞 words。找出 s 中剛好能夠由 words 中全部單詞串聯造成的子串的起始位置。bash
注意子串要與 words 中的單詞徹底匹配,中間不能有其餘字符,但不須要考慮 words 中單詞串聯的順序。微信
示例 1:app
輸入: s = "barfoothefoobarman", words = ["foo","bar"] 輸出:[0,9] 解釋: 從索引 0 和 9 開始的子串分別是 "barfoo" 和 "foobar" 。 輸出的順序不重要, [9,0] 也是有效答案。
示例 2:spa
輸入: s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"] 輸出:[]
思路:滑動窗口code
先用最簡單的思路去嘗試看可否解決問題。題目中說明要咱們找到子串與 words 的單詞徹底匹配。那麼最簡單的思路就是判斷子串是否符合,符合就將索引放到列表中,最後返回。blog
具體的作法如上圖,循環遍歷索引,判斷子串是否符合。這裏主要的問題是如何判斷子串是否符合?索引
題目中有個提示【注意子串要與 words 中的單詞徹底匹配,中間不能有其餘字符,但不須要考慮 words 中單詞串聯的順序。】,也就是說題目中並不要求子串徹底按照順序,只須要對應個數相等且中間鏈接部分不會有其餘字符。這樣就算匹配。leetcode
這裏,咱們能夠藉助哈希表解決。一個哈希表存儲 words 的信息,鍵存儲的是單詞,值存儲的是單詞出現的個數。另一個哈希表一樣鍵存儲的是單詞,值存儲單詞出現的個數,這個哈希表在遍歷字符串的同時進行維護,而後與前面的哈希表中的值進行比對。這裏會出現以下狀況:rem
但這裏其實沒必要移動 1 個字符去匹配。題目有說起【一些長度相同的單詞 words】,也就是說 words 中的單詞的長度都是同樣的。這樣,每次移動就能夠移動的偏移量就是單詞的長度。
那麼對單詞使用滑動窗口,步長就是單詞的長度 word_len。那麼在 0 ~ word_len 的範圍內,這裏每一個都做爲滑動窗口的起點,進行滑動,就能覆蓋全部字符串的組合。
下圖爲示例 1 以及使用滑動窗口的大體圖解:
示例 1
輸入: s = "barfoothefoobarman", words = ["foo","bar"] 輸出:[0,9]
具體實現的代碼以下。
class Solution: def findSubstring(self, s: str, words: List[str]) -> List[int]: from collections import Counter # 處理特殊狀況 if not s or not words: return [] # 哈希表統計單詞出現次數,用之後續比較 word_cnt = Counter(words) # 單詞長度 word_len = len(words[0]) # 返回結果列表 ans = [] # 遍歷,進行窗口滑動 for i in range(word_len): left = i right = i cnt = 0 # 哈希表記錄窗口的單詞出現次數 window = Counter() # 限定邊界 # 這裏表示窗口的內容不足以組成串聯全部單詞的子串,循環結束 while left + len(words) * word_len <= len(s): # 窗口單詞出現的次數,與 word_cnt 對比 while cnt < len(words): word = s[right:right+word_len] # 若是單詞不在 words 中,或者此時單詞數量大於 words 中的單詞數量時,退出循環另外處理 # 單詞次數相等也跳出另外判斷 # 不然更新哈希表 window if (word not in words) or (window[word] >= word_cnt[word]): break window[word] += 1 cnt += 1 right += word_len # 先判斷哈希表是否相等,相等則加入返回列表中 if word_cnt == window: ans.append(left) # 再處理單詞數溢出的狀況 # 區分在於單詞是否在 words 中 if word in words: # 剔除左邊部分 left_word = s[left: left+word_len] window[left_word] -= 1 left += word_len cnt -= 1 else: # 若是單詞不在 words 中, # 清空哈希表,重置窗口開始位置 right += word_len window.clear() left = right cnt = 0 return ans
文章原創,若是感受寫得還好,歡迎關注點贊。微信公衆號《書所集錄》同步更新,一樣歡迎關注。