1.双指针
1.1滑动窗口
1.11定长型滑动窗口
题目特征:存在一个固定长度(k)的子串,寻找其中的符合条件的元素个数
解题步骤:
先定义右边界,对右边界的元素开始遍历,当有边界的元素满足条件时进入统计,此时再定义右边界left=right-k+1;(因为窗口长度为k,也就是right-left+1=k,就可以反解出left),当left<0时(此时窗口还未形成)所以continue;令右端点继续向后移动。当left==0时进行答案的更新(此步骤需按题目而定)。当left>0时,开始让左端点元素出窗口,此时对右端点元素进行判断,如果满足条件就需要对统计数据进行更改。
时间复杂度O(n)只进行了一次遍历

1.12不定长滑窗
此类题目大体上特征为:求最长/短子数组or子数组个数
此类题目大概率涉及了hash表部分的内容
(1)最长/短子串型
以该题为例,该题表面上是删除0后的最长非零子数组, 但该题可以简化思路,因为数组中只含有0/1两种数字,所以题目目标可以改成寻找只含有一个零的最长串(但是因为需要删除一个元素,统计长度的时候应该减去1)
做题步骤:因为窗口不定长,所以left不与right绑定,两个便单独定义就行,依旧先遍历右窗口元素,并统计边界条件元素,当边界元素不满足题目条件时,开始缩小窗口将left向右进行移动,并对边界元素的个数进行更新,当while维护结束后,此时就是满足条件的窗口,就可以开始更新答案

`
c++
class Solution {
public:
int longestSubarray(vector<int>& nums) {
//转换题意得求只含1个零的最长子数组
int cnt0=0;
int ans=0;
for(int right=0,left=0;right<nums.size();right++){
cnt0+=1-nums[right];
while(cnt0>1){
cnt0-=1-nums[left];//对统计数据开始更新
left++;
}
ans=max(ans,right-left);//因为必须减去一个元素所以该题长度应该少一
}
return ans;
}
};
(2)越长越满足类型(窗口越长时,满足题目条件的子串越多)
该类题型在更新答案时,一般会ans+=left, 因为此类题型我们应该更加趋于关注left-1时能否满足条件从而确定left的值,当left被确定时[left-1,right],[left-2,right],[left-3,right]...[0,right]的子串都满足条件,数量就是left-1-0+1个也就是left个

做题步骤:
依旧遍历右端点,对满足条件的数据进行统计,当统计数据达到题目要求时就可以开始缩小窗口寻找不满足条件的left**(while条件是满足题目要求的条件,因为找的是不满足时恰好位置)**,并同时对统计数据进行更新,当while完成维护时此时就找到了恰好不满足条件的左端点位置,根据 上面的推导可以得知此时满足条件的子串个数为left
c++在这里插入代码片
class Solution {
public:
long long countSubarrays(vector<int>& nums, int k) {
int max_num=range::max(nums.begin(),nums.end());
int cnt=0;
long long ans=0;
for(int right=0,left=0;right<nums.size();right++){
if(nums[right]==max_num){
cnt++;
}
while(cnt>=k){
if(nums[left]==max_num){
cnt--;
}
left++;
}
ans+=left;
}
return ans;
}
};
(3)越短越满足(窗口越长短,满足题目条件的子串越多)
此类题目在更新答案时大概率需要**ans+=right-left+1;**因为在while循环时结束时此时的[left,right]是符合要求的区间,其内部的子串[left+1,right].[left+2,right]...[right,right]都是满足条件的,所以总数也就是区间长度

做题步骤:
依旧依旧遍历右端点,对满足条件的数据进行统计,当统计数据不满足条件时,开始缩小条件,当while**(条件为不满足题目的条件,因为该种题型需要的是缩小至刚好全部满足条件的子串的最大集合)**结束维护时,就可以更新答案了
c++
class Solution {
public:
long long countSubarrays(vector<int>& nums, long long k) {
long long ans=0,sum=0;
for(int right=0,left=0;right<nums.size();right++){
sum+=nums[right];
while(sum*(right-left+1)>=k){
sum-=nums[left];
left++;
}
ans+=right-left+1;
}
return ans;
}
};
``