题目:
Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: “abcabcbb”
Output: 3
Explanation: The answer is “abc”, with the length of 3.
Example 2:
Input: “bbbbb”
Output: 1
Explanation: The answer is “b”, with the length of 1.
Example 3:
Input: “pwwkew”
Output: 3
Explanation: The answer is “wke”, with the length of 3.
Note that the answer must be a substring, “pwke” is a subsequence and not a substring.
解答:
本题运用了滑动窗算法的思路,其中:
- 使用了双指针 left,right,分别代表当前窗口的起始和结束位置,
- 用hashset记录当前窗口中存在的字符元素
- 整体思路是保持窗口起始处(左指针 left)固定不变,移动窗口结束处(右指针 right)。若当前窗口结束处(右指针 right 所指)字符未出现在 hashset 中,则该字符不重复,更新 result 结果值并继续右移窗口结束处(右指针 right)。若当前窗口结束处(右指针 right 所指)字符已出现在 hashset 中,则从 hashset 中移除窗口起始处(左指针 left 所指)字符,右移 left ,并继续判断右指针 right 是否重复(右指针 right 可能与当前窗口中的某字符重复,所以需要多次判断,直至删除掉重复字符,保持 set 中字符唯一性)
- 每次更改窗口结束处(右指针 right )时,都更新 result 的值,取更新后长度与上次长度的最大值
class Solution {
public int lengthOfLongestSubstring(String s) {
HashSet<Character> set = new HashSet<>();
int left = 0;
int right = 0;
int result = 0;
while(left<s.length() && right<s.length()) {
if(!set.contains(s.charAt(right))) {
set.add(s.charAt(right));
result = Math.max(result,right-left+1);
right++;
}else {
set.remove(s.charAt(left));
left++;
}
}
return result;
}
}
滑动窗口思想
滑动窗口是一种常用到的解题思想。
一般是基于双指针进行求解,对数组或者字符串进行遍历时,两个指针一前一后夹着子数组或子串,从而确定一个窗口,通过控制前后指针的移动,来控制窗口的大小和范围。通常也会用到一些特定的数据结构,如 hashmap 等。
解题的大体思路:先保持左指针不动,移动右指针,右指针每往前移动一格,都会有新一个元素进入窗口,这时条件可能就会发生改变,然后根据当前条件来决定左指针是否移动,以及移动多少格。具体问题基于以上具体求解即可
如本题中例 3 的滑动窗口的滑动遍历过程,[ ] 分别表示窗口的起始和结束位置
[ p w ] w k e w
[ p w w ] k e w
p [ w w ] k e w
p w [ w ] k e w
p w [ w k ] e w
p w [ w k e ] w
p w [ w k e w ]
p w w [ k e w ]
常见的应用场景:通常应用于主数组和子数组,或主串和子串的关系问题
如:
- 最小覆盖子串(给你一个字符串 S,一个字符串 T,请在字符串 S 里面找出包含 T 所有字母的最小子串),具体见 LeetCode 第 76 题
- 长度最小的子数组(给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组),具体见 Leetcode 第 209 题
- 替换后的最长重复字符,具体见 LeetCode 第 424 题
- 找到字符串中所有字母异位词,具体见 LeetCode 第 438 题
- 字符串的排列,具体见 LeetCode 第 567 题