LeetCode 3. 無重複字元的最長子串(滑動視窗圖解)
3. 無重複字元的最長子串
題目描述
給定一個字串 s,請你找出其中不含有重複字元的最長子串的長度。
範例 1
1 | |
範例 2
1 | |
範例 3
1 | |
限制
0 <= s.length <= 10^5s由英文字母、數字、符號和空格組成
本文題解程式碼整理自 LeetCode 題解作者「灵茶山艾府」,題解連結。思路說明與圖解為自行補充。
前置知識:不定長滑動視窗
前幾篇(2841、2461、1423)的視窗長度都固定為 k。這題的視窗長度不固定:right 往右走一格就把新字元加入視窗,如果視窗內出現重複,就不斷把 left 往右移(縮小視窗),直到沒有重複為止。
每個字元最多被 right 加入一次、被 left 移出一次,所以整體是 O(n)。
兩種寫法的差別只在於「怎麼記錄視窗裡有哪些字元」:
- 寫法一:用計數表
cnt,記錄每個字元在視窗內出現幾次。先加入再檢查,cnt[c] > 1就縮小。 - 寫法二:用集合
has,只記錄視窗內有沒有這個字元。先檢查再加入,has[c]為真就先縮小,沒有重複才加入。
方法一:哈希表(整型陣列計數)
思路
right向右枚舉,把c = s[right]的計數加一。- 若
cnt[c] > 1,代表視窗內有重複,用while不斷移出左端字元(cnt[s[left]]--、left++),直到cnt[c] == 1。 - 此時視窗內沒有重複,用
right - left + 1更新答案的最大值。
圖解(可互動)
用範例 1:s = "abcabcbb"。注意第 3 個字元 a 再次出現時,cnt["a"] 變成 2,視窗會縮小到把舊的 a 移出為止。
s = "abcabcbb"(先加入,有重複再縮小)
窗口 [left, right]
造成重複的字元
入 = 剛加入
出 = 剛移出
窗口長度0
最長長度 ans0
解法(灵茶山艾府)
1 | |
複雜度分析
- 時間複雜度:O(n),其中 n 為
s的長度。注意left至多增加 n 次,所以整個二重迴圈至多循環 O(n) 次。 - 空間複雜度:O(|Σ|),其中 |Σ| 為字元集合的大小,本題中字元均為 ASCII 字元,所以 |Σ| ≤ 128。
方法二:哈希集合(布林陣列)
思路
視窗內不可能有重複字元,所以其實不需要知道「出現幾次」,只要知道「有沒有」就夠了:
right向右枚舉,c = s[right]。- 加入
c之前先檢查:若視窗內已經有c(has[c]為真),再加入就會重複,所以先用while不斷移出左端字元(has[s[left]] = false、left++),直到視窗內沒有c。 - 加入
c(has[c] = true),用right - left + 1更新答案的最大值。
圖解(可互動)
同樣用範例 1。和方法一比較:這裡在遇到重複時,是先縮小、再加入,所以窗口不會短暫出現重複字元。
s = "abcabcbb"(先縮小到沒重複,再加入)
窗口 [left, right]
造成重複的字元
入 = 剛加入
出 = 剛移出
窗口長度0
最長長度 ans0
解法(灵茶山艾府)
1 | |
複雜度分析
- 時間複雜度:O(n),其中 n 為
s的長度。left至多增加 n 次,所以整個二重迴圈至多循環 O(n) 次。 - 空間複雜度:O(|Σ|),本題中字元均為 ASCII 字元,所以 |Σ| ≤ 128。
LeetCode 3. 無重複字元的最長子串(滑動視窗圖解)
https://shengshengyang.github.io/2026/10/19/leetcode-3-longest-substring-without-repeating/