算法-双指针

目录

1、双指针遍历分割:避免开空间,原地处理

2、快慢指针:循环条件下的判断

3、左右指针(对撞指针):分析具有单调性,避免重复计算

双指针又分为双指针遍历分割,快慢指针和左右指针

1、双指针遍历分割:避免开空间,原地处理

(概念)核心思想:将数组分为两端、已处理的的部分,未处理的部分,cur遍历数组,指向未完成的数组,同时处理数组元素。dest指向处理完成的部分。

算法实际操作:cur指向第一个待处理的元素。dest指向处理完元素存放的位置,根据 cur指向数据的类型,进行不同操作。

例题:移动零

1089. 复写零 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n=nums.size();
        for(int cur=0,dest=-1;cur<nums.size();){
            if(nums[cur]){//非0的顺序不变,那么按序处理非0
                swap(nums[cur],nums[++dest]);
            }
            cur++;
        }
    }
};
cpp 复制代码
class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur=0,dest=-1,n=arr.size();
        while(cur<n){
            if(arr[cur]) dest++;
            else dest+=2;
            if(dest>=n-1) break;
            cur++;
        }

        if(dest==n){
            arr[n-1]=0;
            dest=n-2;cur--;
        }
        while(cur>=0){
            if(arr[cur]) arr[dest--]=arr[cur--];
            else{
                arr[dest--]=0;
                arr[dest--]=0;
                cur--;
            }
        }
    }
};

2、快慢指针:循环条件下的判断

核心思想:经过分析,对于存在循环情况的问题,我们可以设置快慢指针来处理

.快乐数ss

cpp 复制代码
class Solution {
public:
    int bitsum(int n){
        int sum=0;
        while(n){
            int i=n%10;
            n/=10;
            sum+=i*i;
        }
        return sum;
    }

//快慢指针,不论是否是快乐数,都会进入循环,要不循环1为快乐数,要不是一堆数依次循环
    bool isHappy(int n) {
        int slow=n,fast=bitsum(n);
        while(slow!=1){
            slow=bitsum(slow);
            fast=bitsum(bitsum(fast));
            if(slow==fast&&slow!=1)
            return false;
        }
        return true;

    }
};

快乐数:分析可知必存在循环,分为1循环和多个数循环,然后利用快慢指针在循环中的前进速率不同,若相遇,判断循环数为多少,即可判断是否是快乐数

3、左右指针(对撞指针):分析具有单调性,避免重复计算

核心思想:在暴击解法上,利用单调性,避免重复计算,

11. 盛最多水的容器 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int maxArea(vector<int>& height) {
        int n=height.size();
        int left=0,right=n-1;
        int ret=(right-left)*min(height[left],height[right]);//记录最大值
        while(left<right){
            if(height[left]<=height[right]){
                left++;
            }else{
                right--;
            }
            ret=max(ret,(right-left)*min(height[left],height[right]));
        }
        return ret;
    }
};

实现操作:定义左右指针,left=0,right=n-1,ret=H*W,left和right向中间靠近的话,w一定减小,h只有增大才能实现ret变大。

611. 有效三角形的个数 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur=0,dest=-1,n=arr.size();
        while(cur<n){
            if(arr[cur]) dest++;
            else dest+=2;
            if(dest>=n-1) break;
            cur++;
        }

        if(dest==n){
            arr[n-1]=0;
            dest=n-2;cur--;
        }
        while(cur>=0){
            if(arr[cur]) arr[dest--]=arr[cur--];
            else{
                arr[dest--]=0;
                arr[dest--]=0;
                cur--;
            }
        }
    }
};

暴力枚举三层循环

简化:排序后,固定两个值------三角形中较大的那两个,然后移动较小的那个值,变成求在某一有序区间内大于某值的个数。(利用单调性)

LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) {
        int n=price.size();
        int low=0,height=n-1;
        while(low<height){
            if(price[low]+price[height]<target){
                low++;
            }else if(price[low]+price[height]>target){
                height--;
            }
            else{
                break;
            }
        }
        return {price[low],price[height]};
    }
};

暴力枚举+利用单调性优化:类盛水容器

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n=nums.size();
        vector<vector<int>> ret;

        for(int k=0;k<n-2;){
            int left=k+1,right=n-1;
            int target=-nums[k];
            while(left<right){
                if(nums[left]+nums[right]<target){
                    left++;
                }else if(nums[left]+nums[right]>target){
                    right--;
                }
                else{
                    ret.push_back(vector<int>{nums[k],nums[left],nums[right]});
                    left++;right--;
                    while(left<right&&nums[left]==nums[left-1])left++;//细节问题:不重复同时判断不越界:left<right
                    while(left<right&&nums[right]==nums[right+1])right--;
                }
            }
            k++;
            while(k<n-2&&nums[k]==nums[k-1])k++;
        }
        return ret;
    }
};

18. 四数之和 - 力扣(LeetCode)

类上,对内两层的暴力改为求目标值

cpp 复制代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int n=nums.size();
        sort(nums.begin(),nums.end());
        vector<vector<int>> ret;

        for(int x=0;x<n-3;){//固定第一个数
            for(int k=x+1;k<n-2;){//固定第二个数
                long long targeti=(long long)target-(nums[x]+nums[k]);
                for(int left=k+1,right=n-1;left<right;){
                    long long sum=nums[left]+nums[right];
                    if(sum>targeti){
                        right--;
                    }else if( targeti>sum){
                        left++;
                    }else{
                        
                        ret.push_back(vector<int>{nums[x],nums[k],nums[left],nums[right]});
                        left++;
                        right--;
                        while(left<right&&nums[left]==nums[left-1]) left++;//注意仅仅,找到target去重,未找到的话,前面那个值未被统计不同去重
                        while(left<right&&nums[right]==nums[right+1]) right--;
                    }
                   
                }
            k++;
            while(k<n-2&&nums[k]==nums[k-1]) k++;
            }
        x++;
        while(x<n-3&&nums[x]==nums[x-1]) x++;
        }
        return ret;
    }
};
相关推荐
地平线开发者3 分钟前
征程 6X watchdog 问题分析
算法·自动驾驶
像素猎人5 分钟前
蓝桥杯OJ716【限定第一步和最后一步爬台阶的经典例题】【动态规划】
c++·算法·动态规划
Q741_1479 分钟前
每日一题 力扣 3474. 字典序最小的生成字符串 贪心 字符串 C++ 题解
c++·算法·leetcode·贪心
人道领域11 分钟前
LeetCode【刷题日记】:螺旋矩阵逆向全过程,边界缩进优化
算法·leetcode·矩阵
ALex_zry13 分钟前
物联网数据质量控制系统设计:质控算法与实现
物联网·算法·struts
EQUINOX116 分钟前
货物运输问题,前缀和优化dp,[牛客周赛137 F-小苯的糖果盒]
算法·动态规划
小此方19 分钟前
Re:从零开始的 C++ STL篇(九)AVL树太“较真”,红黑树更“现实”:一文讲透工程中的平衡之道
开发语言·数据结构·c++·算法·stl
地平线开发者19 分钟前
多 Batch 量化校准与单 Batch 校准的数值差异
算法·自动驾驶
少许极端19 分钟前
算法奇妙屋(三十八)-贪心算法学习之路 5
java·学习·算法·贪心算法
im_AMBER23 分钟前
Leetcode 150 最小路径和 | 最长回文子串
数据结构·算法·leetcode