Problem Description
給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 因爲無重複字符的最長子串是 "abc",所以其長度爲 3。
示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 因爲無重複字符的最長子串是 "b",所以其長度爲 1。
示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 因爲無重複字符的最長子串是 "wke",所以其長度爲 3。
請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
思路
這道題如果用暴力的話時間複雜度是O(n^2),所以我們需要想辦法進行優化,怎麼優化呢?
因爲暴力中有很多操作是多餘的,比如遇到相同的字符時就沒必要再執行下去了,因此我們就需要從這個地方下手,
利用雙指針滑動窗口,維護窗口中不允許有重複的字符出現,一旦有重複字符,就更新窗口,讓窗口的begin指針前移,知道窗口中沒有重複字符爲止,
下面以abcabcbb作爲示例進行演示:(期間還需要一個數組flag,用於記錄某個字符是否出現過)
最開始的時候begin指針和i指針都在字符串的起始位置
然後i指針不斷前移,直到走到這裏,發現flag[a]爲1,a出現過,此時就需要更新begin指針
將begin指針移動到<begin,i>這個窗口中沒有重複字符,然後 i 繼續++,需要更新begin指針時,繼續更新窗口
下面結合代碼再捋一遍
代碼
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.length() < 2){
return s.length();
}
int flag[128] = {0};//用於存滑動窗口內字符出現的次數,以便更新窗口
int begin = 0;//雙指針滑動窗口
int ans = 0;
for(int i = 0; i < s.length(); i++){
if(flag[s[i]] >= 1){ //說明字符s[i]出現過,此時需要更新滑動窗口的begin指針
while(flag[s[i]]){ //begin更新到窗口內沒有重複字符的地方
flag[s[begin]]--;
begin++;
}
}
flag[s[i]]++;//標記字符
ans = max(ans,i-begin+1);
}
return ans;
}
};