一.双指针思想
1.分类:同向双指针,反向双指针
2.优点:可以将两层循环嵌套的问题优化成一层循环
3.常见情况
<1>利用快慢双指针确定链表的中间节点,链表是否带环,带环链表的入环点在哪里
<2>一次循环解决需要两次循环遍历顺序表的问题
<3>剩余情况需要根据题目具体考量
4.例题
<1>题目:283.移动零(. - 力扣(LeetCode))
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
<2>算法思想:
1)定义两个指针cur,dest:让cur指向数组的nums[0],用来遍历数组;让dest指向nums[-1],用来确定非零元素和零元素的分界线
2)当cur指向的元素为0时,cur++;当cur指向的元素不为0时,让dest++,同时交换两个指针指向的元素,cur++
<3>代码实现:
class Solution {
public:
void moveZeroes(vector<int>& nums) {
for(int cur=0,dest=-1;cur<nums.size();++cur)
{
if(nums[cur]!=0)
{
swap(nums[++dest],nums[cur]);
}
}
}
};
二.滑动窗口
1.本质:有具体大小的由同向双指针控制的区域
2.使用限制:数组数据只能是正数
注:该思想是根据单调性,当在某处可以完成要求后,若再进数据势必不会是所求的可能结果
3.使用模板:
<1>初始化两个指针:left,right
<2>数据进窗口
<3>判断是否满足条件,出数据
<4>根据实际情况,更新结果
4.正确性:利用单调性,规避了很多一定不成立的情况
5.例题
<1>题目:209.长度最小的子数组(. - 力扣(LeetCode))
给定一个含有 n
个正整数的数组和一个正整数 target。
找出该数组中满足其总和大于等于 target
的长度最小的。
<2>算法思想:
1)定义两个指针left,right,均指向数组中第一个元素
2)进窗口:让right指向的元素进入[left,right]的窗口内
3)判断:若是窗口内元素之和大于等于目标值,计算此时窗口的长度,更新最小长度,同时让left指向的元素出窗口;若不满足则right继续向后移动带着元素进入窗口
<3>代码实现:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left=0,right=0;
int sum=0,n=nums.size(),len=INT_MAX;
for(;right<n;++right)
{
sum+=nums[right];//进窗口
while(sum>=target)
{
len=min(len,right-left+1);//更新最小长度
sum-=nums[left++];//出窗口
}
}
return len==INT_MAX?0:len;
}
};