滑动窗口
理论讲解
算法的应用场景
满足XXX条件(计算结果,出现次数,同时包含)
出现最长,最短时
字串/子数组/子序列
如:长度最小的子数组
滑动窗口的使用思路(寻找最长)
**核心:**左右双指针(L,R)最开始在起始点,然后R向右诸位滑动循环
每次滑动过程中:
如果窗内元素满足条件,R向右扩大窗口,并更新最优结果
如果窗内元素满足条件,L向右,缩小窗口
R到达结尾
最长模板
初始化left,right,result,bestRresult
while(右指针没有到结尾){
窗口扩大,加入right对应的元素,更新result//该位置要视情况而定,也可以放到while循环下面
while(result不满足要求){
窗口缩小,移除left对应元素,left右移
}
更新最优结果bestResult
right++;
}
例题:3. 无重复字符的最长子串
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DeEqub5g-1661679992517)(C:\Users\wu\AppData\Roaming\Typora\typora-user-images\image-20220729130905492.png)]
class Solution {
public int lengthOfLongestSubstring(String s) {
int l=0,r=0,res=0;
Set<Character> occ = new HashSet<Character>();
while(r<s.length()&&l<=r){
while(occ.contains(s.charAt(r))){
occ.remove(s.charAt(l));
l++;
}
occ.add(s.charAt(r));
res=r-l+1>res?r-l+1:res;
r++;
}
return res;
}
}
滑动窗口的使用思路(寻找最短)
**核心:**左右双指针(L,R)最开始在起始点,然后R向右诸位滑动循环
每次滑动过程中:
如果窗内元素满足条件,L向右缩小窗口并更新最优结果
如果窗内元素满足条件,R向右扩大窗口
R到达结尾
最短模板
初始化left,right,result,bestRresult
while(右指针没有到结尾){
窗口扩大,加入right对应的元素,更新result
while(result满足要求){
更新最优结果bestResult
窗口缩小,移除left对应元素,left右移
}
right++;
}
例题:209. 长度最小的子数组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-86eUzp0A-1661679992519)(C:\Users\wu\AppData\Roaming\Typora\typora-user-images\image-20220729131107814.png)]
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left=0,right=0;
int sum=0;
int res=nums.length+1;
while(right<nums.length){
sum=sum+nums[right];
while(sum>=target){
res=right-left+1<res?right-left+1:res;
sum=sum-nums[left];
left++;
}
right++;
}
return res==nums.length+1?0:res;
}
}
另一种模板
滑动窗口有两种解决问题的思想
其一:
左指针一次移动一格**for(int L=0,L<length,L++)**然后右指针按照要求遍历左指针之后的元素.
右指针R在【L,end】的区间内,搜索结果。一般时while循环中自增R++。直到不满足循环条件
如3. 无重复字符的最长子串的另一种解法
class Solution {
public int lengthOfLongestSubstring(String s) {
// 哈希集合,记录每个字符是否出现过
Set<Character> occ = new HashSet<Character>();
int n = s.length();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rk = -1, ans = 0;
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.remove(s.charAt(i - 1));
}
while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
// 不断地移动右指针
occ.add(s.charAt(rk + 1));
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = Math.max(ans, rk - i + 1);
}
return ans;
}
}
其二:
右指针一次移动一格**for(int R=0,R<length,R++)**然后左指针按照要求遍历右指针之前的元素.
左指针R在【0,R】的区间内,搜索结果。一般时while循环中自增L++。直到不满足循环条件
如209. 长度最小的子数组的另一种解法
class Solution {
// 滑动窗口
public int minSubArrayLen(int s, int[] nums) {
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= s) {
result = Math.min(result, right - left + 1);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
476

被折叠的 条评论
为什么被折叠?



