前言
今天我们的题都是关于滑动窗口的,首先我们先来介绍一下滑动窗口是什么。
滑动窗口
滑动窗口其实也是一种双指针,用于解决数组问题中,查找某个连续子数组中最值的一种解决办法。其核心思路是右指针每次向右遍历,给窗口扩大,然后检查此时窗口是否符合条件,如果符合,就收缩直至不符合,收缩过程记得更新窗口相关的变量。更新之前或者之后一般要寻找最佳答案,我们根据下面的题目进行具体分析。
int l=0;//滑动窗口左端点
for(int i=0;i<nums.length;i++){//滑动窗口右端点
//扩张阶段
...
//收缩阶段
while(check()){
...
}
}
题目
038、长度最小的子数组
题目描述
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的
子数组
[numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
解题思路
我们用一个sum记录窗口中元素的和,收缩的条件就是sum>=target
代码
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int l=0;
int len=nums.length;
int ans=Integer.MAX_VALUE;
long sum=0;
for(int r=0;r<len;r++){
//扩张
sum+=nums[r];
//收缩
while(sum>=target){
//寻找最佳答案
ans=Math.min(ans,r-l+1);
//更新窗口相关的变量
sum-=nums[l++];
}
}
if(ans==Integer.MAX_VALUE)return 0;
return ans;
}
}
039、水果成篮
题目描述
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。
解题思路
分析一下,我们要做其实是看一段连续数组中,最多两种水果的数目之和的最大值,肯定还是滑动窗口来做。
我们用一个HashMap记录窗口中水果的种类及数量,收缩的条件就是map.size()>2
代码
class Solution {
public int totalFruit(int[] fruits) {
int l=0,r=0;
int len= fruits.length;
Map<Integer,Integer> mp=new HashMap<>();
int temp=0;
int ans=0;
for(r=0;r<len;r++){
//扩张
mp.put(fruits[r],mp.getOrDefault(fruits[r],0)+1);
//收缩
while(mp.size()>2){
temp=mp.get(fruits[l]);
mp.put(fruits[l],temp-1);
if(temp-1==0)mp.remove(fruits[l]);
l++;
}
//寻找答案
int sum=0;
for(Integer v:mp.values()){
sum+=v;
}
ans=Math.max(sum,ans);
}
return ans;
}
}
040、最小覆盖子串
题目描述
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
解题思路
分析一下,我们要做其实是看s的一段连续子串中,是否出现了t中的全部字母及个数。我首先想到的使用哈希表记录字母和个数,肯定还是滑动窗口来做。
我们用一个HashMap mps记录窗口中的字母以及个数,用一个HashMap mpt记录t串中的字母以及个数,收缩的条件(check)就是mps包含mpt中的所有元素,并且value不小于mpt的value。
代码
class Solution {
//定义全局变量,方便其他方法使用
Map<Character,Integer> mps=new HashMap<>();
Map<Character,Integer> mpt=new HashMap<>();
public boolean check(){
for(Character c:mpt.keySet()){
if(mps.get(c)==null)return false;
if(mps.get(c)<mpt.get(c)){
return false;
}
}
return true;
}
public String minWindow(String s, String t) {
int l=0,len=s.length();
int ansl=0,ansr=Integer.MAX_VALUE;
//初始化mpt
char[] tt=t.toCharArray();
for(char c:tt){
if(mpt.get(c)==null){
mpt.put(c,1);
}else{
mpt.put(c,mpt.get(c)+1);
}
}
//开始滑动
for(int r=0;r<len;r++){
//扩张
mps.put(s.charAt(r),mps.getOrDefault(s.charAt(r),0)+1);
//收缩
while(check()){
//记录答案的起止
if((r-l)<(ansr-ansl)){
ansl=l;
ansr=r;
}
mps.put(s.charAt(l),mps.get(s.charAt(l))-1);
if(mps.get(s.charAt(l))==0)mps.remove(s.charAt(l));
l++;
}
}
if(ansr==Integer.MAX_VALUE)return "";
return s.substring(ansl,ansr+1);
}
}
结语
暑假已经不足一半,希望能够刷够一百题