双指针算法:解锁算法迷宫的神奇之钥

✨✨✨学习的道路很枯燥,希望我们能并肩走下来!


前言

本篇详细介绍了双指针的使用,让使用者了解双指针算法,而不是仅仅停留在表面,更好的模拟,为了更好的使用. 文章可能出现错误,如有请在评论区指正,让我们一起交流,共同进步!


提示:以下是本篇文章正文内容,下面案例可供参考

一、双指针算法是什么?

常见的双指针有三种形式:前后指针、对撞指针、快慢指针

双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。

换言之,双指针法充分使用了数组有序这一特征,从而在某些情况下能够简化一些运算。(往往能降低一个次方的时间复杂度)

 1.1 对撞指针

对撞指针是指在数组中,将指向最左侧的索引定义为左指针(left),最右侧的定义为右指针(right),然后从两头向中间进行数组遍历。

 对撞数组适用于连续数组和字符串,也就是说当你遇到题目给定连续数组和字符床时,应该第一时间想到用对撞指针解题。

 1.2 快慢指针

快慢指针也是双指针,但是两个指针从同一侧开始遍历数组,将这两个指针分别定义为快指针(fast)慢指针(slow),两个指针以不同的策略移动直到两个指针的值相等(或其他特殊条件)为止,如 fast 每次增长两个,slow 每次增长一个。 

1.3 前后指针 

1、前后指针:用于顺序结构,一般是两个指针同方向,cur指针用来遍历数组,des指针将数组进行区域划分。(如1、2题) 

二、双指针算法的应用

2.1 移动零

移动零

 

 

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]);
        }
    }
};

 2.2 复写0

 1089. 复写零 - 力扣(LeetCode)

 

 

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur = 0, dest = -1 , n = arr.size();
        //1.找最后一个复写的数
        while(cur<n)
        {
            if(arr[cur])
                dest++;
            else
                dest+=2;
            if(dest>=n-1)
                break;
            cur++;
        }
        //2. 处理边界问题(即cur移动到数组最后一个位置,该位置为0
        if(dest == n)
        {
            arr[n-1]=0;
            cur--;
            dest-=2;
        }
        //3 从右向左复写
        while(cur>=0)
        {
            if(arr[cur])
                arr[dest--]=arr[cur--];
            else
            {
                arr[dest--] = 0;
                arr[dest--] = 0;
                cur--;
            }
        }
    }
};

 2.3 快乐数

202. 快乐数 - 力扣(LeetCode)

 

class Solution {
public:
    int Sum(int n)
    {
        int sum = 0;
        while(n)
        {
            int t = n%10;
            sum += t*t;
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        int slow = n ,fast = Sum(n);
        while(slow != fast)
        {
            slow = Sum(slow);
            fast = Sum(Sum(fast));
        }
        return slow == 1;
    }
};

 2.4 盛最多水的容器

 

class Solution {
public:
    int maxArea(vector<int>& height) {
        int left = 0, right = height.size()-1 , ret = 0;
        while(left<right)
        {
            int v = min(height[left],height[right])*(right-left);
            ret = max(ret,v);
            if(height[left]<height[right]) 
                left++;
            else
                right--;
        }
        return ret;
    }
};

 2.5 有效三角形的个数

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

 

 

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        //1.优化区间
        sort(nums.begin(),nums.end());
        //2.固定最大值
        int ret = 0, n = nums.size();
        for(int i = n-1;i>=2;i--)
        {
            //3.利用双指针快速统计符合要求的三元组的个数
            int left = 0, right = i-1;
            while(left<right)
            {
                if((nums[left]+nums[right])>nums[i])
                {
                    ret+= right - left;
                    right--;
                }
                else
                {
                    left++;
                }
            }
        }
        return ret;
    }
};

 2.6 查找总价格为目标值的两个商品

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

 

class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) {
        int left = 0,right = price.size()-1;
        while(left<right)
        {
            if((price[left]+price[right])<target)
                left++;
            else if((price[left]+price[right])>target)
                right--;
            else
                return {price[left],price[right]};//隐式类型转化
        }
        //考虑编译器,解决:non-void function does not return a value in all control paths,让所有路径都有返回值
        return {};
    }
};

2.6 三数之和

15. 三数之和 - 力扣(LeetCode)

 

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //排序,方便我们
        sort(nums.begin(),nums.end());
        //2.固定
        vector<vector<int>> ret;
        int n = nums.size();
        for(int i = 0;i<n;)
        {
            if(nums[i]>0) break; //优化固定区间
            int left = i+1;
            int right = n-1;
            int target = -nums[i];
            while(left<right)
            {
                int sum = nums[left]+nums[right];
                if(sum>target)
                    right--;
                else if(sum<target)
                    left++;
                else
                {
                    ret.push_back({nums[i],nums[left],nums[right]});
                    left++,right--;
                    while(left<right&&nums[left]==nums[left-1]) left++; //越界问题处理+去重
                    while(left<right&&nums[right]==nums[right+1]) right--;
                }
            }
            i++;//越界问题处理+去重
            while(i<n&&nums[i]==nums[i-1]) i++;
        }

        return ret;

        
    }
};

2.7 四数之和 

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

 

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        //1.排序
        sort(nums.begin(),nums.end());
        //2.双指针
        vector<vector<int>> ret;
        int n = nums.size();
        for(int i = 0;i<n;)
        {
            for(int j = i+1;j<n;)
            {
                //三数之和
                int left = j+1;
                int right = n-1;
                long long aim = (long long)target - nums[i]-nums[j]; //用longlong防止数据溢出
                while(left<right)
                {
                    int sum = nums[left]+nums[right];
                    if(sum>aim) right--;
                    else if(sum<aim) left++;
                    else
                    {
                        ret.push_back({nums[i],nums[j],nums[left++],nums[right--]});
                        //去重1
                        while(left<right&&nums[left]==nums[left-1]) left++;
                        while(left<right&&nums[right]==nums[right+1]) right--;
                    }
                }
                //去重2
                j++;
                while(j<n&&nums[j]==nums[j-1]) j++;
            }
            //去重3
            i++;
            while(i<n&&nums[i]==nums[i-1]) i++;
        }
        return ret;
        
    }
};

总结

✨✨✨各位读友,本篇分享到内容是否更好的让你理解了双指针算法,如果对你有帮助给个👍赞鼓励一下吧!!
🎉🎉🎉世上没有绝望的处境,只有对处境绝望的人。
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!。

  • 26
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值