3. 無重復字符的最長子串
知識點:字符串,滑動窗口
題目描述
給定一個字符串 s ,請你找出其中不含有重復字符的 最長子串 的長度。
示例
輸入: s = "abcabcbb"
輸出: 3
解釋: 因為無重復字符的最長子串是 "abc",所以其長度為 3。
輸入: s = "bbbbb"
輸出: 1
解釋: 因為無重復字符的最長子串是 "b",所以其長度為 1。
輸入: s = "pwwkew"
輸出: 3
解釋: 因為無重復字符的最長子串是 "wke",所以其長度為 3。
請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
輸入: s = ""
輸出: 0
解法一:滑動窗口
滑動窗口其實就是一種隊列;
對於本題,依次入隊,當發現這個隊列中含有重復元素的時候,把重復元素之前的值全部移除。比如 a b c a b;到第二個a的時候將a出隊;
如果不用隊怎么實現,其實就是維持了一個滑動着的窗口,右邊界依次在遍歷,左邊界也在移動,而且注意左邊界一定不會回退的。當遍歷到的元素出現過了的時候,要把左邊界移動;
其次不能有重復元素 -- > 哈希表;
用哈希表存儲每個字符和字符出現的索引,當出現重復字符的時候,移動左邊界;注意兩種情況:
- a b c a; 第二個a的時候要把左邊界移動到a的下一個處,相當於a出隊;
- a b b a; 到達第2個b的時候因為之前含有b了,所以map.get(b)+1,也就是左邊界到了2,但是到下一個a的時候,如果還用同樣的,那left = map.get(a)+1 = 1,就又回去了,所以應該取兩者中的大值;相當於a b出隊;出去的可千萬別再進來了;滑動窗口的左右邊界是永遠不會回退的。
一句話:沒有觸發條件,右窗口一直移動;達到觸發條件,左窗口移動,促使條件再次不滿足;,在這個題里,條件就是窗口內是否有重復字符;
class Solution {
public int lengthOfLongestSubstring(String s) {
int len = s.length();
int maxLen = 0;
int left = 0;
Map<Character, Integer> map = new HashMap<>(); //為了檢查重復,存儲字符和其出現的索引;
for(int i = 0; i < len; i++){
if(map.containsKey(s.charAt(i))){
left = Math.max(left, map.get(s.charAt(i))+1); //左窗口移動;左右邊界永不回頭;
}
map.put(s.charAt(i), i);
maxLen = Math.max(maxLen, i-left+1);
}
return maxLen;
}
}