字串最長子串難?滑動視窗拯救你
題目:leetcode 3. 無重複字元的最長子串
給定一個字串,請你找出其中不含有重複字元的 最長子串 的長度。
示例 1:
輸入: s = "abcabcbb"
輸出: 3
解釋: 因為無重複字元的最長子串是 "abc",所以其長度為 3。
子串:串中任意個連續的字元組成的子序列稱為該串的子串。
解題思路
要求字串的不含有重複字元的最長子串的長度,只需要先找到最長子串然後再求其長度即可,找最長子串我們可以通過滑動視窗的方法去查詢。
滑動視窗
滑動視窗就是通過不斷調整子序列的 start 和 end 位置,從而獲取滿足要求的結果。
具體操作如下:
-
假設已經找到一個不含重複字元子串 s[left...right],s[left...right] 表示從字串 s 的下標 left 到 right 的子串。
-
子串陣列的右邊界 right 向右移,拓展子串長度,以尋找最長子串。
-
將字元 s[right + 1] 跟子串 s[left...right] 中的每個字元進行比較,如果都不同,則將字元 s[right + 1] 也納入到子串中。
如果字元 s[right + 1] 跟子串 s[left...right] 中的某個字元相同,則將子串陣列的左邊界 left 右移,刨除 s[left...right] 中的那個重複的字元;
刨除前
刨除後
-
left 到 right 這個區間形成一個滑動視窗,為了尋找滿足條件的子串,視窗不停地在向前滑動,記錄子串的長度是否是更長的子串。
細節
如何判斷右邊界 right 向右拓展時,其對應的字元和當前找到的子串中無重複字元呢?一個簡單的方法是:設定一個數組記錄 ASCII 碼出現的頻率,這樣當 right 向右拓展時,就可以查詢其對應的字元對應的 ASCII 碼在該陣列中相應的頻率值的多少判斷是否出現了重複字元。
Show me the Code
1 // c 語言 2 int lengthOfLongestSubstring(char * s){ 3 int res = 0; 4 int len = strlen(s); 5 /* 記錄 ASCII 字元在子串中出現的次數 */ 6 int freq[256] = {0}; 7 /* 定義滑動視窗為 s[l...r] */ 8 int l = 0, r = -1; 9 while (l < len) { 10 /* freq 中不存在該字元,右邊界右移,並將該字元出現的次數記錄在 freq 中 */ 11 if (r < len - 1 && freq[s[r + 1]] == 0) { 12 freq[s[++r]]++; 13 /* 右邊界無法拓展,左邊界右移,刨除重複元素,並將此時左邊界對應的字元出現的次數在 freq 的記錄中減一 */ 14 } else { 15 freq[s[l++]]--; 16 } 17 /* 當前子串的長度和已找到的最長子串的長度取最大值 */ 18 res = fmax(res, r - l + 1); 19 } 20 return res; 21 }
1 // c++ 語言 2 int lengthOfLongestSubstring(string s) { 3 int res = 0; 4 int len = s.size(); 5 int freq[256] = {0}; 6 int l = 0, r = -1; 7 while (l < len) { 8 if (r + 1 < len && freq[s[r + 1]] == 0) { 9 freq[s[++r]]++; 10 } else { 11 freq[s[l++]]--; 12 } 13 res = max(res, r - l + 1); 14 } 15 return res; 16 }View Code
更多精彩
關注公眾號 『 TanLiuYi00 』回覆「演算法」,即可獲取經典高清無碼演算法與資料結構相關電子書