开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情 这也是第39篇文章
前言
这篇文章的主题是——滑动窗口。
是什么
首先简要说说什么是滑动窗口。
这个“窗口”是一个假想的概念,它有固定的范围,但它前后边界指向的地方会变化,就像滑动了一样,因此称为 滑动窗口 。
以下是一个很简单、直观的入门级解释。
以数组[1,2,3]为例,有一个大小为2的滑动窗口,一开始窗口框住了1,2,后来窗口往前移动了一位,框住了[2,3]。它就像滑动了一样。
滑动窗口也可理解为是距离保持不变的双指针。
有什么用
从我做过的题来看,可以简化搜索、确定范围等等。
剑指 Offer 48. 最长不含重复字符的子字符串
题目
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
思路
这个子字符串的区间就可以看做是一个窗口,因此可以用滑动窗口的思想去做。i作为左指针,r作为右指针,当右指针遇到重复字符时,左指针跳到子串里第一个重复字符的位置,并通过set把子串中重复字符前的字符去掉,右指针继续往右扩展。
代码实现
class Solution {
public int lengthOfLongestSubstring(String s) {
int n=s.length();
int res=0,r=-1;
HashSet<Character> set=new HashSet<>();
for(int i=0;i<n;i++){
if(i!=0) set.remove(s.charAt(i-1));
while(r+1<n&&!set.contains(s.charAt(r+1))){
set.add(s.charAt(r+1));
r++;
}
res=Math.max(res,r-i+1);
}
return res;
}
}
剑指 Offer II 009. 乘积小于 K 的子数组
题目
给定一个正整数数组
nums和整数k,请找出该数组内乘积小于k的连续的子数组的个数。
思路
和第一题类似,右指针每次都往右扩展,如果遇到不符合条件的情况,就缩短左区间。
每次区间的大小就是这一轮包含的子数组的个数。
代码实现
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
int cnt=0;
int n=nums.length;
int tmp=1;
int i=0,j=0;
while(j<n){
tmp*=nums[j];
while(i<=j&&tmp>=k){
tmp/=nums[i];
i++;
}
cnt+=(j-i)+1;
j++;
}
return cnt;
}
}