題目:
給定乙個字串,請你找出其中不含有重複字元的 最長子串 的長度。
示例 1: 輸入: 「abcabcbb」 輸出: 3 解釋: 因為無重複字元的最長子串是 「abc」,所以其長度為 3。從示例 3 可以看出來,子串必須是連續的。示例 2: 輸入: 「bbbbb」 輸出: 1 解釋: 因為無重複字元的最長子串是 「b」,所以其長度為 1。
示例 3: 輸入: 「pwwkew」 輸出: 3 解釋: 因為無重複字元的最長子串是 「wke」,所以其長度為 3。
請注意,你的答案必須是 子串 的長度,「pwke」 是乙個子串行,不是子串。
分析:「滑動視窗」的思想比較容易想到,用兩個指標 i 和 j;
將 i 固定在開始,j 移動,如果沒有重複則繼續移動 j ,一旦重複就記錄距離,這是乙個「無重複字元」的子串的長度;
接著 i 就可以直接跳到 j 的位置(因為 j 是重複元素),j 繼續移動,重複上面的過程,更新每次的子串的長度。
具體的實現來說:
如果使用列表,在查詢「有沒有重複」的過程裡,一般是要遍歷前面已有的所有位置,那麼在總共的兩重迴圈下,時間複雜度會達到 o(n) ,好處是在找到重複之後就立刻知道重複的元素是誰,可以將 i 跳到 j ;
如果查詢「有沒有重複」的過程希望複雜度位 o(1) 那麼可以使用雜湊表,但是雜湊表的儲存一般沒有順序,沒法按下標,所以 i 的挪動只能「按值」將最早加入雜湊表的那個字元刪掉,也就是子串的最前面乙個字元,這樣外迴圈是連續的 o(n) ;
讓雜湊表也能刪除連續的好幾個元素。
直接利用資料結構 hashset,我們以示例 1 來模擬過程,「abcabcbb」,要找出最長的子串:
「a b c a b c b b」
a,加入集合;
b,加入集合;
c,加入集合;
a,已經有 a 了,重複,此時子串最大長度是 3 。從集合刪除最前面的 a ,此時剩下 b c;
a,加入集合;
b,已有 b ,重複,此時最長長度為 b c a 是3。從集合中刪除最前面的 b ,此時剩下 c a;
b,加入集合;
c,已有 c ,重複,此時最長長度為 c a b 是3。從集合中刪除最前面的 c,此時剩下 a b;
c,加入集合;
b,已有 b,重複,此時最大長度為 a b c 是3。(雖然我們希望從集合中直接刪除 a 和 b,畢竟直接從 c 開始才有意義。但是由於 set 無法記錄下標,辦不到,只能移除乙個最前面的 a ,然後繼續進行判斷)。從集合中刪除 a,此時剩下 b c;
b,已有 b,重複,此時最大長度是 b c 是2。從集合中刪除 b,剩下 c;
b,加入集合;
b,已有 b,重複,此時最大長度是 c b 是2。從集合中刪除 c,剩下 b(注意,仍然沒辦法直接刪完);
b,已有 b,重複,刪除 b ,刪除後集合已經空;
b,加入集合。
**做法很簡單:
我們需要額外的乙個指標,遍歷字串的 i 是其中的乙個,總是代表子串的開始,還需要乙個 end 指標代表子串的最右邊。
//對於整個s遍歷一遍,時間複雜度為 o(n) 。
for(
int i=
0;ilength()
;i++
)//最右邊出現重複元素之後 end 還要後移,避免超範圍用 end+1 來判斷
while
(end+
1length()
&&!set.
contains
(s.charat
(end+1)
))//更新ans,用下標之差來計算,由於上一步判斷用的是 end+1 所以距離要+1.
ans=math.
max(ans,end-i+1)
;}
加上初始化和特殊情況的判斷,就可以寫出完整**.
ans 的初始值顯然為 0,那麼 end 的初始值應該為 0 嗎?
考慮到開始 set 為空,那麼第一次執行 add 操作的時候, add( end+1 ) 加進去的是下標為 0 的字元,所以end的初始值應該設為 -1。
完整**:
class
solution
setset=
newhashset
<
>()
;int ans=0;
int end=0;
for(
int i=
0;ilength()
;i++
)while
(end+
1length()
&&!set.
contains
(s.charat
(end+1)
))ans=math.
max(ans,end-i+1)
;}return ans;
}}
上一種方法的弊端我們已經討論過,對於子串的開始指標 i 和結束指標 j ,找到重複之後就立刻知道重複的元素是誰,可以將 i 跳到 j,這一點做不到。
考慮到 ascii 碼值總共只有 128 個,所以我們可以用對應的碼值,也就是charat(i) 作為下標,自己建立乙個雜湊表,用陣列的值記錄「 某乙個字元出現過的次數」 :
class
solution
ans=math.
max(ans,end-i+1)
;//當前這個不重複子串的長度和已有ans取最大值
}return ans;
}}
這段**的核心就是 while 部分,假如是 「 a b c d c 」 的話:
繼續下乙個子串,開始就是 i 在 end 的位置
力扣(LeetCode) 3 無重複字串
3.無重複字串 給定乙個字串,請你找出其中不含有重複字元的 最長子串 的長度。示例 1 輸入 abcabcbb 輸出 3 解釋 因為無重複字元的最長子串是 abc 所以其長度為 3。示例 2 輸入 bbbbb 輸出 1 解釋 因為無重複字元的最長子串是 b 所以其長度為 1。示例 3 輸入 pwwk...
力扣3 無重複字元的最長子串
給定乙個字串,請你找出其中不含有重複字元的 最長子串 的長度。示例 1 輸入 abcabcbb 輸出 3 解釋 因為無重複字元的最長子串是 abc 所以其長度為 3。示例 2 輸入 bbbbb 輸出 1 解釋 因為無重複字元的最長子串是 b 所以其長度為 1。示例 3 輸入 pwwkew 輸出 3 ...
力扣 3 無重複字元的最長子串
3.無重複字元的最長子串 給定乙個字串,請你找出其中不含有重複字元的最長子串的長度。示例 1 輸入 abcabcbb 輸出 3解釋 因為無重複字元的最長子串是 abc 所以其長度為 3。示例 2 輸入 bbbbb 輸出 1解釋 因為無重複字元的最長子串是 b 所以其長度為 1。示例 3 輸入 pww...