LeetCode 力扣 3 無重複字元的最長子串

2021-10-07 02:10:44 字數 3162 閱讀 8977

題目:

給定乙個字串,請你找出其中不含有重複字元的 最長子串 的長度。

示例 1: 輸入: 「abcabcbb」 輸出: 3 解釋: 因為無重複字元的最長子串是 「abc」,所以其長度為 3。

示例 2: 輸入: 「bbbbb」 輸出: 1 解釋: 因為無重複字元的最長子串是 「b」,所以其長度為 1。

示例 3: 輸入: 「pwwkew」 輸出: 3 解釋: 因為無重複字元的最長子串是 「wke」,所以其長度為 3。

請注意,你的答案必須是 子串 的長度,「pwke」 是乙個子串行,不是子串。

從示例 3 可以看出來,子串必須是連續的。

分析:「滑動視窗」的思想比較容易想到,用兩個指標 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...