最长不重复的字串
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
解题思路:
- 方法一:暴力求解遍历该字符串的所有字串。然后判断字串中是否含有重复的字符。该方法可以求出答案 但是运行速度真的太慢了。比如:S[i:j]表示 s字符串的i到j之间的字串。我们判断S[i:j]是否含有相同的字符。那么,当我们字串遍历到s[i+1:j] s[i+1:j+1] s[i:j+1] 等情况时候。我们会发现子字符串 s[i-1:j-1] 的子字符串被重复判断了多次。由此 我们考虑第二种方法 ☟
- 方法二:最理想的情况: 当我们判断s[i:j+1]是否有重复字符时 只需要判断s[j:j+1] 是否是 s[i:j]的字串即可。因为我们s[i:j]已经判断过了。 这样 本题目就转化为一个判断区间内的字符是否重复。 维护好这个区间即可。 滑动窗口即是本题的解决方案
解题步骤:定义两个变量left、right代表窗口的左右位置。用一个set来存当前窗口内的字符。当新来一个字符时:判断该字符是否已经在窗口中出现。如果出现:缩小窗口,移除窗口左值。加入窗口右值。 如果没有出现:扩大窗口,加入新来的字符。计算当前的窗口值并和旧窗口值取最值。将窗口的右边的值+1。 废话不多说 直接上代码
public int lengthOfLongestSubstring(String s) {
int ans = 0;
Set<Character> set = new HashSet<>();
int left = 0; // 窗口左值
int right = 0; // 窗口右值
int len = s.length();
while (left < len && right < len){
if(!set.contains(s.charAt(right))){
set.add(s.charAt(right++));
ans = Math.max(ans,right - left);
}else {
set.remove(s.charAt(left ++));
}
}
return ans;
}
总结: 滑动窗口的思想是在编程题中经常遇到的一种解决方案。特别在遍历求值的题目中。暴力美学固然有效。但同时要考虑时间复杂度和空间复杂度。减少重复遍历。