LeetCode-3 無重複字符的最長子串 Longest Substring Without Repeating Characters

題目

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

示例 1:

輸入: “abcabcbb”
輸出: 3
解釋: 因爲無重複字符的最長子串是 “abc”,所以其長度爲 3。
示例 2:

輸入: “bbbbb”
輸出: 1
解釋: 因爲無重複字符的最長子串是 “b”,所以其長度爲 1。
示例 3:

輸入: “pwwkew”
輸出: 3
解釋: 因爲無重複字符的最長子串是 “wke”,所以其長度爲 3。
請注意,你的答案必須是 子串 的長度,“pwke” 是一個子序列,不是子串。

思路

我知道,對某個問題想出最佳解法固然難得,然而要將自己的想法解釋給他人聽懂則更爲難得。

對於這個問題,可以使用滑動窗口的方法來解決。
可以將字符串視爲一條鐵軌,而滑動窗口則是鐵軌上的一輛列車。列車的長度可以伸縮,每節列車對應鐵軌上的一個字符。

  1. 首先固定列車的尾部,將列車的頭部向前延伸,每延伸一節,就查看新加的這一節對應的鐵軌上的字符是否在列車中出現過,沒出現過則繼續延伸。
  2. 如果出現過,則將列車的長度-1就是到當前位置最大的無重複子串長度,記爲maxlen。
  3. 固定列車的頭部,將列車的尾部向前延伸,即縮短列車的長度,直到重複的情況消除。
  4. 重複步驟2-3,比較每次的maxlen,取較大者。直到列車頭部到達鐵軌終點,再取一次maxlen比較。

寫代碼

對於上述思路,在寫代碼的過程中可以進一步優化。思路在於,當出現重複時,我們將列車尾部逐漸前移,直到重複消除,如果能使尾部直接移到重複位置的下一個位置,則可以大大節約時間。

  1. 考慮使用一個hash-map,int m[128], 記錄每個字符上一次出現的位置。並記錄列車尾部的位置last.
  2. 列車頭部前進時,每遇到一個字符c,就檢查它上一次出現的位置m[c],如果m[c]>=last,則說明此字符在列車中出現過,更新maxlen,將l移至m[c]+1的位置,並更新m[c]爲列車頭部位置。
  3. 重複步驟2,直到字符串結尾,再更新一次maxlen。

附代碼

/*
思路:記錄子串的開頭和結尾下標,並記錄子串中每個字符的下標。
將結尾位置後移,如果新加入的字符上一次出現的下標大於開頭,則說明此字符重複
將當前子串大小-1,並與result比較,取較大者
將開頭移到上一次出現此字符的位置之後一位
繼續後移結尾
*/
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int result=0;
        vector<int> m(128,-1);//用於記錄每個字符上一次出現的位置的下標
        
        int size=s.size();
        int f=0;//子串開頭
        int l=0;//子串結尾
        
        //將l後移直到出現重複
        while(l!=size)
        {
            if(m[s[l]]<f) m[s[l]]=l;//如果s[l]上一次出現的位置小於f,說明在當前子串中s[l]不重複
            
            else//出現了重複,就把f向後移到消除重複的位置
            {
                //在此處更新一下result,f到l-1是不重複的
                result=max(result,l-f);
                
                f=m[s[l]]+1;
                m[s[l]]=l;
            }
            
            ++l;//後移l
        }
        
        //l到結尾退出,再更新一下result
        result=max(result,l-f);
        
        return result;
    }
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章