【算法题解答·三】滑动窗口
接上文【算法方法总结·三】滑动窗口的一些技巧和注意事项
滑动窗口相关题目如下:
3.无重复字符的最长子串
- 右边界
right
扩大,直到窗口中有重复字符 - 窗口中有重复字符,则左边界
left
缩小 - 使用 哈希表 来检查窗口中 是否有重复字符
// 先拓展右边界,再在循环中拓展左边界
class Solution {
public int lengthOfLongestSubstring(String s) {
// 使用哈希表来检查窗口中是否有重复字符
Set<Character> set = new HashSet<>();
char[] ss = s.toCharArray();
int len = s.length();
int res = 0;
int left = 0; //左边界
// 右边界
for (int right = 0; right < len; right++) {
char c = ss[right];
// 因为子串是连续的,所以有重复就一直删
while (set.contains(c)) {
set.remove(ss[left]);
left++; //拓展左边界
}
// 没重复了,添加
set.add(c);
res = Math.max(res, right - left + 1); //更新最大值
}
return res;
}
}
438.找到字符串中所有字母异位词
- 异位词,用
c1[26]
和c2[26]
来记录字符数 - 此题为 固定长度 的 滑动窗口
// 用c1[26]和c2[26]来记录字符数,滑动窗口的长度为 p 字符串的长度
// 用遍历1-26的方式来确定c1[]和c2[]对应字母是否
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new ArrayList<>();
int[] c1 = new int[26], c2 = new int[26]; //记录字符数
int n = s.length(), m = p.length();
// 先记录 p 中的字符
for (int i = 0; i < m; i++) {
c2[p.charAt(i) - 'a']++;
}
// 固定长度的滑动窗口
int left = 0; //左边界
for (int right = 0; right < n; right++) {
c1[s.charAt(right) - 'a']++;
if (right - left + 1 > m) { //拓展左边界
c1[s.charAt(left) - 'a']--;
left++;
}
// 确认是异位词
if (check(c1, c2)) {
res.add(left); //首字符下标
}
}
return res;
}
public boolean check(int[] c1, int[] c2) {
for (int i = 0; i < 26; i++) {
if (c1[i] != c2[i])
return false;
}
return true;
}
}
209.长度最小的子数组
- 长度 最小 连续子数组,非常适合 滑动窗口 的方法
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0; // 窗口内的和
int result = Integer.MAX_VALUE; // 记录最小长度
for (int right = 0; right < nums.length; right++) {
sum += nums[right]; // sum < target时,一直向右扩大窗口
while (sum >= target) { // sum >= target时,一直向左缩小窗口
result = Math.min(result, right - left + 1);
sum -= nums[left++]; // 向左缩小窗口
}
}
if (result == Integer.MAX_VALUE) { // 不存在符合条件的子数组
result = 0;
}
return result;
}
}
算法题解答系列
【算法题解答·一】二分法
【算法题解答·二】双指针法
【算法题解答·三】滑动窗口
【算法题解答·四】字符串操作
【算法题解答·五】链表操作
【算法题解答·六】栈队列堆