劍指 Offer 48. 最長不含重複字元的子字串

RainsX 發表於 2021-09-22

劍指 Offer 48. 最長不含重複字元的子字串

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • s.length <= 40000

方法一:動態規劃 + 雜湊表

  • Java 的 getOrDefault(key, default) , 代表當雜湊表包含鍵 key 時返回對應 value ,不包含時返回預設值 default。
  • tmp<j-i時候,tmp+1,即dp[j]=dp[j-1]+1
  • tmp>=j-i時候,j-i,即dp[j]=j-i
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int res = 0, tmp = 0;
        for(int j = 0; j < s.length(); j++) {
            int i = dic.getOrDefault(s.charAt(j), -1); // 獲取索引 i
            dic.put(s.charAt(j), j); // 更新雜湊表
            tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
            res = Math.max(res, tmp); // max(dp[j - 1], dp[j])
        }
        return res;
    }
}

方法二:雙指標 + 雜湊表

做題思路:

迴圈索引j遍歷字元s,然後如果查詢到重複數則更新左指標i,否則繼續記錄雜湊表,更新res結果,最後再返回res即可

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int i = -1, res = 0;
        for(int j = 0; j < s.length(); j++) {
            if(dic.containsKey(s.charAt(j)))
                i = Math.max(i, dic.get(s.charAt(j))); // 更新左指標 i
            dic.put(s.charAt(j), j); // 雜湊表記錄
            res = Math.max(res, j - i); // 更新結果
        }
        return res;
    }
}

除了這兩個之外,k神還有一個方法。

方法三: 動態規劃 + 線性遍歷

與方法一、二的程式碼有點類似,除了在while那裡為了實現線性查詢有點變化。

  • 左邊界 ii 獲取方式: 遍歷到 s[j]s[j] 時,初始化索引 i = j - 1i=j−1 ,向左遍歷搜尋第一個滿足 s[i] = s[j]s[i]=s[j] 的字元即可 。
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int res = 0, tmp = 0;
        for(int j = 0; j < s.length(); j++) {
            int i = j - 1;
            while(i >= 0 && s.charAt(i) != s.charAt(j)) i--; // 線性查詢 i
            tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
            res = Math.max(res, tmp); // max(dp[j - 1], dp[j])
        }
        return res;
    }
}

參考連結:

https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/mian-shi-ti-48-zui-chang-bu-han-zhong-fu-zi-fu-d-9/