今天是紀錄LeetCode解題的第三十天
成功堅持一個月了!剛好今天也是困難題
第三十題題目:
You are given a string s and an array of strings words. All the strings of words are of the same length.
A concatenated string is a string that exactly contains all the strings of any permutation of words concatenated.
Return an array of the starting indices of all the concatenated substrings in s. You can return the answer in any order.
給定一個字串s和數組words,所有words裡的字串長度都相同,請找出所有的起始索引,使得從該索引開始的子字串,是words中所有字串的串接(concatenation)
傳回所有連接子字串的起始索引數組,可以按任意順序返回答案
我們利用滑動視窗的方式,一次擷取words中的字串的長度大小,如果擷取的字串存在於words中,那就計算該字串出現的次數,如果出現的次數大於words中字串的次數,那麼我們就縮小左邊邊界,直到縮減至小於等於我們要找的次數,如果總次數等於words總字串次數,這時候的左邊界left就是我們要找的索引值
from collections import Counter
class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
word_len = len(words[0])
word_count = len(words)
total_len = word_len * word_count
s_len = len(s)
if s_len < total_len:
return []
target = Counter(words)
result = []
for offset in range(word_len):
left = offset
right = offset
window_count = Counter()
count = 0
while right + word_len <= s_len:
word = s[right:right+word_len] #擷取字串
right += word_len #右移
if word in target: #如果找到的字串是要找的
window_count[word] += 1 #計算該字串次數
count += 1 #計算所有字串出現次數
while window_count[word] > target[word]:#如果出現的字串次數大於要尋找的字串次數
left_word = s[left:left+word_len] #左邊開始收縮
window_count[left_word] -= 1
left += word_len
count -= 1
if count == word_count:
result.append(left)
else:
window_count.clear()
count = 0
left = right
return result
Counter是一種特別的「字典(dict)」,專門用來「統計元素出現次數」
基本用法
from collections import Counter
s = "leetcode"
counter = Counter(s)
print(counter)
#輸出:Counter({'e': 3, 'l': 1, 't': 1, 'c': 1, 'o': 1, 'd': 1})
Counter也可以用在List
from collections import Counter
words = ["foo", "bar", "foo", "bar", "bar"]
c = Counter(words)
print(c)
#輸出:Counter({'bar': 3, 'foo': 2})
初始狀態
offset = 0
滑動視窗繼續右移
滑動視窗繼續右移
開始收縮左邊界
繼續收縮左邊界
照這個概念依此類推就能找出答案,以上演示如何模擬滑動視窗不斷向右擷取字串,以及收縮左邊界減少擷取字串的執行過程,這題雖然是hard題,但觀念不會太難