實作一個函數 strStr(haystack, needle)
,用來找出字串 needle
在字串 haystack
中第一次出現的索引。如果 needle
不是 haystack
的一部分,則返回 -1
。
輸入:
haystack = "sadbutsad", needle = "sad"
輸出:
0
解釋:needle
出現在 haystack
的索引 0 和 6 處。第一次出現在索引 0 處,所以回傳 0。
輸入:
haystack = "leetcode", needle = "leeto"
輸出:
-1
解釋:needle
不在 haystack
中。
要解決這個問題,我們需要從以下角度考慮:
needle
是否存在於 haystack
中。-1
。我們可以從最簡單的暴力匹配到更高效的演算法(如 KMP 演算法)進行討論。
思路
使用兩層迴圈:
haystack
的每個字符作為起始位置。needle
匹配。詳細步驟
haystack
:程式碼實現
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if not needle:
return 0
m, n = len(haystack), len(needle)
for i in range(m - n + 1):
if haystack[i:i + n] == needle:
return i
return -1
時間與空間複雜度
haystack
的長度,n 是 needle
的長度。思路
暴力解法在每次失敗匹配時會回退至下一個起始位置,這會導致重複計算。KMP 演算法通過預處理 needle
,構建一個「部分匹配表」(partial match table),在匹配失敗時快速跳過不必要的字符。
部分匹配表(LPS)的構建
LPS(Longest Prefix which is also Suffix)表記錄了 needle
的每個字符之前的最長前綴後綴匹配長度。
步驟:
n
的數組 lps
,所有值為 0。needle
,更新前綴後綴匹配長度。詳細步驟
當匹配失敗時,根據 LPS 表跳過多餘的字符。
程式碼實現
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if not needle:
return 0
def buildLPS(pattern):
lps = [0] * len(pattern)
length = 0
i = 1
while i < len(pattern):
if pattern[i] == pattern[length]:
length += 1
lps[i] = length
i += 1
else:
if length != 0:
length = lps[length - 1]
else:
lps[i] = 0
i += 1
return lps
lps = buildLPS(needle)
i = j = 0
while i < len(haystack):
if haystack[i] == needle[j]:
i += 1
j += 1
if j == len(needle):
return i - j
elif i < len(haystack) and haystack[i] != needle[j]:
if j != 0:
j = lps[j - 1]
else:
i += 1
return -1
時間與空間複雜度
希望這篇教學能幫助大家更理解 LeetCode 第 28 題的解法!