題目
給定一個字符串 s 命浴,請你找出其中不含有重復(fù)字符的 最長子串 的長度娄猫。
示例 1:
輸入: s = "abcabcbb"
輸出: 3
解釋: 因為無重復(fù)字符的最長子串是 "abc",所以其長度為 3生闲。
示例 2:
輸入: s = "bbbbb"
輸出: 1
解釋: 因為無重復(fù)字符的最長子串是 "b"媳溺,所以其長度為 1。
示例 3:
輸入: s = "pwwkew"
輸出: 3
解釋: 因為無重復(fù)字符的最長子串是 "wke"跪腹,所以其長度為 3褂删。
請注意,你的答案必須是 子串 的長度冲茸,"pwke" 是一個子序列屯阀,不是子串缅帘。
示例 4:
輸入: s = ""
輸出: 0
題解
滑動窗口
思路
所謂滑動窗口,即為兩個左右指針难衰,通過左右指針的單向滑動钦无,來遍歷元素,最終得到結(jié)果盖袭。
- 首先明確失暂,需要遍歷字符串,求子串(不能剔除元素)鳄虱,那么怎么遍歷所有子串呢弟塞?
int n = s.length();
for (int left = 0; left < n; left++) {
for (int right = 0; right < n; right++) {
}
}
這是暴力解法,不是滑動窗口拙已,那么怎么能簡化暴力解到滑動窗口呢决记?
- [left,right]范圍內(nèi)的滑動窗口倍踪,保存不重復(fù)的字符系宫,如果字符不重復(fù),right不斷右移建车,直到遇到重復(fù)字符扩借,left右移一位,right不動缤至,left右移后潮罪,再次進(jìn)行字符重復(fù)性判斷和right的移動
- left左指針遍歷規(guī)則不變,left指針每次右移的時候凄杯,right指針不回縮到left+1位置错洁,因為沒有必要,為什么呢戒突?
- [left,right]范圍內(nèi)是不重復(fù)子串,那么[left+1描睦,right]范圍肯定也是不重復(fù)的膊存,right也就沒有必要回縮,繼續(xù)在原來位置進(jìn)行新一輪的重復(fù)性判斷和移動就可以了
- 遇到重復(fù)字符忱叭,left右移后隔崎,如果left新位置字符和right處字符重復(fù),則left繼續(xù)右移韵丑,如果不重復(fù)爵卒,那么right處原本重復(fù)的字符變成了不重復(fù),被添加到窗口中了撵彻,這樣right就沒有回縮钓株,而是不斷的往右移動
代碼
private static int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> diffrent = new HashSet<>();
// 右指針
int right = -1;
int max = 0;
// 左指針
for (int left = 0; left < n; left++) {
// 不重復(fù)的右指針不斷右移实牡,同時加到set中
while (right + 1 < n && !diffrent.contains(s.charAt(right + 1))) {
diffrent.add(s.charAt(right + 1));
right++;
}
// 出現(xiàn)重復(fù)字符,此時可求得一個不重復(fù)字符的子串轴合,和之前最大長度比較创坞,求最大,注意此時重復(fù)的字符還沒有加到set中
max = Math.max(max, diffrent.size());
// 左指針右移一位受葛,因為此時left位置到right位置不重復(fù)题涨,那么left+1位置到right位置肯定也不會重復(fù)
// 如果left位置是重復(fù)字符,那么移除后新一輪就變成了不重復(fù)字符加到了set中总滩,如果left位置不重復(fù)纲堵,那新一輪還是重復(fù)字符,left繼續(xù)右移一位
diffrent.remove(s.charAt(left));
}
return max;
}