劍指 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;
}
}
參考連結: