Leetcode題解 Python:Substring with Concatenation of All Words

給一字串 s 跟 words 字串串列,問哪些位置可以找到全部在words中的詞只出現一次。
思路很簡單,想辦法在一個 n 的時間讓全部都搜過。(用搜尋法倒很隨意)
有一個條件可以利用,那就是每個 word 都是一樣的長度,因此不必逐字元去判斷,可以拿詞去匹配。
於是產生原型的逐詞匹配,但這還不夠!速度還太慢。
每當遇到這種匹配題型,盡可能不要反覆同一位置重複匹配。之前有提到一個方式 KMP,若全照用,這裡可能會在 prefix table 產生太多組合 。
因為 words 的詞沒有指定先後順序,所以要是當前位置沒有匹配到,就可把最前面匹配的放回待匹配的隊伍,繼續匹配,若都沒有可匹配,那就往下移動。

Python(逐詞匹配)

class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
result = []
if not s or not words: return result
counter = Counter(words)
nowCounter = counter.copy()
i = 0
m = len(words[0])
n = len(s)
n2 = len(words)
while i <= n-m*n2:
nowCounter = counter.copy()
for j in range(n2):
word = s[i+j*m:i+m+j*m]
if word in nowCounter:
if nowCounter[word] > 0:
nowCounter[word] -= 1
if nowCounter[word] == 0:
del nowCounter[word]
else:
break
if not nowCounter: result.append(i)
i += 1
return result

Python(逐詞匹配2)

class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
result = []
if not s or not words: return result
wl = len(words[0])
wn = len(words)
counter = Counter(words)
select = list()
n = len(s)
def search(pos, wi):
if pos+wl > n:
while select: counter[select.pop(0)] += 1
return
word = s[pos: pos+wl]
while select and (word not in counter or counter[word] == 0):
counter[select.pop(0)] += 1
wi -= 1
if word in counter and counter[word] > 0:
counter[word] -= 1
select.append(word)
if wi+1 == wn: result.append(pos - wi*wl)
search(pos+wl, wi+1)
else:
search(pos+wl, wi)
for i in range(wl):
search(i, 0)
return result