1. 程式人生 > >【探索-中級演算法】無重複字元的最長子串

【探索-中級演算法】無重複字元的最長子串

在這裡插入圖片描述


1.

參考自:https://juejin.im/post/5aa159f86fb9a028bb189420

思路:
初始化一個 255 的 boolean 陣列(字元對應的數字作為陣列下標)作為所有可能出現的字元對應的存在可能性,不存在重複的均為 false,存在重複的,則對應的下標置為 true。

兩個指標進行移動,前指標先不動,後指標移動並根據當前字元對應整數下標是否為 false 或者 true 進行判斷。如果是 false,則表示沒有重複,則指標向後移動一位;如果為 true,表示存在重複,則後指標停止移動,並計算當前字串長度,且將 boolean 陣列重置,第一個指標向前移動一位,後指標指向當前前指標。

這樣做其實就是普通的遍歷,從字串的第一個字母開始,得到以第一個字母開始的無重複的最大子串 s1,然後從字串的第二個字母開始,得到以第二個字母開始的無重複的最大子串 s2,如此遍歷,得到其中最長的。

public int lengthOfLongestSubstring(String s) {
    if (s == null || s.length() == 0) return 0;
    if (s.length() == 1) return 1;
    int max = 0;
    int firstPoint = 0;
    int nextPoint = 0;
    boolean
[] exist = new boolean[255]; int strLen = s.length(); while (nextPoint < strLen) { int index = s.charAt(nextPoint); while (nextPoint < strLen && !exist[index]) { exist[index] = true; nextPoint++; if (nextPoint < strLen)
{ index = s.charAt(nextPoint); } } max = Math.max(max, nextPoint - firstPoint); if(max==len) return len;//如果最大無重複字串即為 s 自身,則直接返回 ++firstPoint; nextPoint = firstPoint; for (int i = 0; i < 255; i++) { exist[i] = false; } } return max; }

最壞情況時間複雜度為 O(n^2)

迴圈次數:n + (n-1) + ... + 1 = n*(n+1) /2  => O(n^2) 

空間複雜度為 O(1)


2.

參考自:
1、https://blog.csdn.net/weixin_38715903/article/details/80520727
2、https://juejin.im/post/5aa159f86fb9a028bb189420
3、https://blog.csdn.net/qq_17550379/article/details/80547777

利用滑動視窗的思想

思路:
以一個 hashmap 作為輔助,map 的 key 儲存的是字元,value 儲存的是該字元當前的位置,首先設定一個頭指標,指向字串開頭,從最開始遍歷字串,如果 map 當中不包含這個字元,那麼用這個字元當前所在的位置減去頭指標的位置,然後與最大長度做比較,選取最大值成為最大長度,然後把當前字元以及位置放入 map。

如果當前字元已經存在於 map 中了,則表示出現了重複字元,那麼把頭指標移動到新重複字元處,即把之前的重複字元頂出去(即滑窗,當然這樣做也會剔除掉原子串中之前那個重複字元前的多個非重複字元,就像下圖中的第七次迴圈),用處於較後位置的重複字元代替,始終保持該字元不重複且處於子串中。

abcabcbb 為例:
在這裡插入圖片描述

public static int lengthOfLongestSubstring2(String s) {
    Map<Character, Integer> map = new HashMap<>();
    int maxLength = 0;
    int head = 0;
    for (int i = 0; i < s.length(); i++) {
        if (map.containsKey(s.charAt(i))) {
            head = Math.max(map.get(s.charAt(i)) + 1, head);
        }
        //(i - head + 1) 為 i 指向的字元距離頭指標指向字元的長度
        if ((i - head + 1) > maxLength)
            maxLength = i - head + 1;
        map.put(s.charAt(i), i);
    }
    return maxLength;
}
head = Math.max(map.get(s.charAt(i)) + 1, head);

head當前字元上次出現位置的下一個字元的位置頭指標原來指向的字元的位置 中的最大位置,考慮 abba 的情況,當 i = 3 時,map.get(s.charAt(3)) + 1 = 1, head = 2,因為當頭指標從 s[0] 移動到 s[2]之後,沒有及時清除掉 map 中的 ('a' -> 0),從而就影響到 map.get(s.charAt(i)) + 1 )。

這裡時間複雜度為 O(n),空間複雜度為 O(1),map 陣列也可用一個可能出現的字元陣列代替(char[255],類似於第 1 點裡面的)。