【算法专题】双指针算法

                          个人主页CSDN_小八哥向前冲

                           所属专栏基础算法


目录

移动零

复写零

快乐数

盛最多水的容器

有效三角形的个数

和为s的两个数

三数之和

四数之和


移动零

题目:【LeetCode】移动零

思路:

这里其实就是一个数组分块的问题,将数组分块即:前一个部分非零,而后一个部分为零。

定义双指针,一个指针(cur)遍历,另一个指针(dest)分割非零和零部分。

cur指针在遍历的过程中有两种情况,一是碰到零和碰到非零,当碰到零时,dest指针不变,cur指针前进一步,碰到非零时,dest前进一步(此时dest是指向零),再和cur指向交换,一直循环这个动作。

图:

代码:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int dest=-1;
        for(int cur=0;cur<nums.size();cur++)
        {
            if(nums[cur])
            {
                swap(nums[++dest],nums[cur]);
            }
        }
    }
};

复写零

题目:【LeetCode】复写零

思路:

利用双指针,我们可以模拟一下从前到后去修改数组,但是发现会覆盖掉原数组的数!

所以,我们可以模拟一下从后到前去修改数组,发现可行!

图:

但是有一个特殊情况:

代码:

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)
        {
            --cur;
            arr[n-1]=0;
            dest-=2;
        }
        //开始就地复写操作
        while(cur>=0)
        {
            if(arr[cur])
            {
                arr[dest--]=arr[cur--];
            }
            else
            {
                arr[dest--]=0;
                arr[dest--]=0;
                --cur;
            }
        }
    }
};

快乐数

题目:【LeetCode】快乐数

题意分析:

思路:

我们可以将它们看成有环的链表,只需判断环内的数是不是1,还是其他数字。

定义快慢指针,快指针走两步,慢指针走一步,当进环后,快指针追上慢指针,判断此时是否为1就解决了!

代码:

class Solution {
public:
    int Happybit(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=Happybit(n);
        while(slow!=fast)
        {
            slow=Happybit(slow);
            fast=Happybit(Happybit(fast));
        }
        return fast==1;
    }
};

盛最多水的容器

题目:【LeetCode】盛水最多的容器

思路:

代码:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int left=0,right=height.size()-1;
        //存较大容器的值
        int ret=0;
        while(left<right)
        {
            //找出较大的值
            int v=min(height[left],height[right])*(right-left);
            ret=max(v,ret);
            //开始挪动
            if(height[left]<height[right])
            {
                left++;
            }
            else
            {
                right--;
            }
        }
        return ret;
    }
};

有效三角形的个数

题目:【LeetCode】有效三角形的个数

思路:

代码:

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n=nums.size(),sum=0;
        int key=n-1;
        //不断取最大的数
        while(key>=2)
        {
            int left=0,right=key-1;
            //每趟
            while(left<right)
            {
                if(nums[left]+nums[right]>nums[key])
                {
                    sum+=right-left;
                    right--;
                }
                else
                {
                    left++;
                }
            }
            key--;
        }
        return sum;
    }
};

和为s的两个数

题目:【牛客】和为s的两个数

思路:

显然,时间太长了,不符合题目要求。

三数之和

题目:【LeetCode】三数之和

思路:

代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> vv;
        sort(nums.begin(),nums.end());
        int n=nums.size();
        for(int key=0;key<n;)
        {
            //当key本身就是大于0的话,那么三数就一定不可能为0
            if(nums[key]>0) break;
            int left=key+1,right=n-1;
            while(left<right)
            {
                int sum=nums[left]+nums[right];
                int targrt=-nums[key];
                if(sum<targrt) left++;
                else if(sum>targrt) right--;
                else
                {
                    vv.push_back({nums[key],nums[left],nums[right]});
                    left++;
                    right--;
                    //去除重复数据,小心越界
                    while(left<right&&nums[left]==nums[left-1]) left++;
                    while(left<right&&nums[right]==nums[right+1]) right--;
                }
            }
            //去重key
            key++;
            while(key<n&&nums[key]==nums[key-1]) key++;
        }
        return vv;
    }
};

四数之和

题目:【LeetCode】四数之和

思路:

代码:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> vv;
        int n=nums.size();
        for(int key1=0;key1<n;)
        {
            for(int key2=key1+1;key2<n;)
            {
                int left=key2+1,right=n-1;
                while(left<right)
                {
                    int sum=nums[left]+nums[right];
                    long long tmp=(long long)target-nums[key1]-nums[key2];
                    if(sum<tmp) left++;
                    else if(sum>tmp) right--;
                    else
                    {
                        vv.push_back({nums[key1],nums[key2],nums[left],nums[right]});
                        left++;
                        right--;
                        //将数据去重,注意越界情况
                        while(left<right&&nums[left]==nums[left-1]) left++;
                        while(left<right&&nums[right]==nums[right+1]) right--;
                    }
                }
                //将key2去重
                key2++;
                while(key2<n&&nums[key2]==nums[key2-1]) key2++;
            }
            //将key1去重
            key1++;
            while(key1<n&&nums[key1]==nums[key1-1]) key1++;
        }
        return vv;
    }
};

这些就是双指针类型常见题目,我们下期见!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值