1. 程式人生 > 其它 >不重複子字串

不重複子字串

請從字串中找出一個最長的不包含重複字元的子字串,計算該最長子字串的長度。

示例1:

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

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

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

思考

暴力法

首先把子串找出來,然後判斷是否重複。判斷是否重複的過程,如果用遍歷的方法就有點low了,這是主要是一個快速查詢,可以用set,其實和去重差不多。

我的思考

這種題,我一般喜歡看看有沒有dp的解法,一般是考慮以每個字元結尾的結果。以abaab為例

  • 如果子串以a結尾,長度為1
  • 如果字串以b結尾,判斷b在之前出現過沒,如果沒有,判斷a出現過沒。
  • 最後找出最大的長度

參考解法

同學提示了下,他說這個其實可以用滑動視窗,具體過程如下、

  • right = 1, left = 0, set維護不重複子串
  • left所指向的字元加入set
  • right所指向的字元如果在set , 說明重複出現,開始計算長度,並把left++, 暴力解法中right執行需要回退到left + 1處,把set清空進入下一次迴圈。但是我們可以進行優化,就是left移動前的對應的元素給刪除了,right不變。現在想想,這其實是利用了不重複子串的left指標前移一次仍然是不重複的,所以沒有必要回退。
  • 這裡程式碼有個坑,當迴圈結束後,還要比較一次set裡的長度和當前長度。如'aq'
class Solution {
    public int lengthOfLongestSubstring(String s) {
        // fast = 1 slow = 0 
        //1. slow 加到map
        // 2. 觀察fast是否可以在map中,如果不再,則fast++,否則slow ++ ,統計長度, slow裡面要刪除. 滑動視窗

        if (s == null || s.length() == 0) {
            return 0;
        }

        char[] chars = s.toCharArray();
        int left = 0;
        int right = 1;
        int len = s.length();
        int result = 1;
        Set<Character> set = new HashSet<>();
        set.add(chars[left]);


        while(right < len) {
            char curChar = chars[right];
            if (set.contains(curChar)) {
                // 統計長度
                result = Math.max(result, right - left);
                set.remove(chars[left]);
                left++;
            } else {
                set.add(curChar);
                right++;
            }
        }

        result = Math.max(result, set.size());
        return result;
    }
}