Description
給定字串
s和字串p,找出s中所有p的 anagram(字母異位詞)的起始索引。回傳索引列表,順序不限。
Example:
Input: s = “cbaebabacd”, p = “abc” Output: [0, 6] (“cba” 和 “bac” 都是 “abc” 的 anagram)
Intuition#
核心思路:固定大小的滑動窗口(大小等於
p的長度),維護窗口內的字元頻率,當頻率與p完全匹配時記錄起始位置。
- 窗口大小固定為
p.length,每次右移一格,加入新字元、移除舊字元 - 用頻率陣列(26 個字母)比較窗口與
p的字元分布 - 優化:維護
matches計數器,追蹤有多少個字母的頻率已匹配,避免每次比較整個陣列
Approaches#
1: Sliding Window + Array Compare#
- 概念: 維護窗口的頻率陣列,每次滑動後比較兩個頻率陣列
- 時間複雜度:
O(n * 26)- 每次滑動比較 26 個字母(n 為 s 的長度) - 空間複雜度:
O(1)- 固定大小的頻率陣列
class Solution {
fun findAnagrams(s: String, p: String): List<Int> {
val result = mutableListOf<Int>()
if (s.length < p.length) return result
val pCount = IntArray(26)
val sCount = IntArray(26)
for (c in p) pCount[c - 'a']++
for (i in 0 until p.length) sCount[s[i] - 'a']++
if (pCount.contentEquals(sCount)) result.add(0)
for (i in p.length until s.length) {
sCount[s[i] - 'a']++
sCount[s[i - p.length] - 'a']--
if (pCount.contentEquals(sCount)) result.add(i - p.length + 1)
}
return result
}
}⭐2: Sliding Window + Matches Counter#
- 概念: 維護
matches計數器,記錄 26 個字母中有幾個頻率已匹配。滑動窗口時只更新受影響的字母,當matches == 26時記錄結果 - 時間複雜度:
O(n)- 每次滑動只做 O(1) 操作 - 空間複雜度:
O(1)- 固定大小的頻率陣列
class Solution {
fun findAnagrams(s: String, p: String): List<Int> {
val result = mutableListOf<Int>()
if (s.length < p.length) return result
val pCount = IntArray(26)
val sCount = IntArray(26)
for (c in p) pCount[c - 'a']++
var matches = 0
for (i in 0 until 26) {
// 初始化:計算第一個窗口
}
for (i in 0 until p.length) {
sCount[s[i] - 'a']++
}
for (i in 0 until 26) {
if (sCount[i] == pCount[i]) matches++
}
if (matches == 26) result.add(0)
for (i in p.length until s.length) {
// 加入右邊新字元
val addIdx = s[i] - 'a'
sCount[addIdx]++
if (sCount[addIdx] == pCount[addIdx]) matches++
else if (sCount[addIdx] == pCount[addIdx] + 1) matches--
// 移除左邊舊字元
val removeIdx = s[i - p.length] - 'a'
sCount[removeIdx]--
if (sCount[removeIdx] == pCount[removeIdx]) matches++
else if (sCount[removeIdx] == pCount[removeIdx] - 1) matches--
if (matches == 26) result.add(i - p.length + 1)
}
return result
}
}🔑 Takeaways#
- Pattern: 固定窗口的 anagram 偵測 -> Sliding Window + 頻率比較
- 關鍵技巧:
matches計數器避免每次比較整個陣列,將每次滑動降到 O(1);此技巧可推廣到所有固定窗口的字元比較問題