双指针系列

001 移动零

1 题目描述

在这里插入图片描述
题目链接

2 思路

在这里插入图片描述

3 代码

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

 

002 复写零

1 题目描述

在这里插入图片描述
题目链接

2 思路

在这里插入图片描述

3 代码

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        
        //正向双指针,找最后一个“复写”的数
        int cur = 0;
        int dest = -1;
        int n = arr.size();

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

        //2、处理特殊情况:dest超出arr的上界
        if(dest > n - 1)
        {
            arr[n-1] = 0;

            //更新边界
            dest-=2;
            --cur;
        }

        //反向从后往前进行复写,此时cur->最后一个复写数,dest->arr中最后一个元素
        while(cur >= 0)
        {
            //arr[cur] != 0,不需要复写0
            if(arr[cur] != 0)
            {
                arr[dest] = arr[cur];
                --dest;
            }
            else//arr[cur] == 0
            {
                //arr[cur] == 0,需要复写0(arr[cur])
                arr[dest] = arr[cur];
                arr[dest - 1] = arr[cur];
                dest -= 2;
            }
            --cur;
        }

    }
};

 

003 快乐数(有环问题)

1 题目描述

在这里插入图片描述
题目链接

2 思路

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3 代码

class Solution {
public:

    //返回num这个数每一位的平方和sum
    int computeNum(int num)
    {
        int sum = 0;
        while(num != 0)
        {
            int result = num % 10;          
            sum =  result*result + sum;
            num = num/10;
        }

        return sum;
    }

明确:如果是快乐树,则它们在环中相遇时快慢指针指向的数肯定为1
如果不是快乐数,则它们在环中相遇时快慢指针指向的数肯定不为1
    bool isHappy(int n) 
    {
        //slow指向第一个数,fast指向第二个数
        int slow = n;
        int fast = computeNum(n);
        fast = computeNum(fast);
        while(fast != slow)
        {
            fast = computeNum(fast);
            fast = computeNum(fast);
            slow = computeNum(slow);
        }

        if(slow == 1)
            return true;
        else
            return false;
    }
};

 

004 盛最多容器的水

题目描述

在这里插入图片描述
题目链接

2 思路

在这里插入图片描述

3 代码

class Solution {
public:
    int maxArea(vector<int>& height) 
    {
        int maxArea = -1;
        int n = height.size();
        int left = 0;
        int right = n - 1;
        while(left < right)
        {
            int computeArea = min(height[left], height[right]) * (right - left);
            
            //数组中其他数与height[left]所组成的体积肯定比computeArea小,不用计算,++left
            if(height[left] < height[right])
            {
                ++left;
            }
            else  //height[left] >= height[right]
            {
                --right;
            }

            maxArea = max(maxArea, computeArea);
        }
        return maxArea;
    }
};

 

005 有效三角形的个数

1 题目描述

在这里插入图片描述
题目链接

2 思路

在这里插入图片描述

3 代码块

class Solution {
public:
    int triangleNumber(vector<int>& nums) {

        sort(nums.begin(),nums.end());
        int n = nums.size();
        int k = 0; //用于统计有效三角形个数 
        for(int i = n-1 ; i >= 2; --i)
        {
            int left = 0;
            int right = i - 1;
            while(left != right)
            {
                if(nums[left] + nums[right] > nums[i])
                {
                //此时[left, right]之间的数与nums[right]和nums[i]所组成的三角片均为合法三角形
                    k = k + (right - left);
                    --right;
                }
                else
                {
                    ++left;
                }                   
            }
        }

        return k;
    }
};

 

006 两数之和

1 题目描述

在这里插入图片描述
题目链接

2 思路

在这里插入图片描述

3 代码

class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) {
        int left = 0;
        int right = price.size() - 1;
        vector<int> res;

        //排序 + 双指针解决
        while(left != right)
        {
            //由于是升序,如果左右指针指向的数,比目标数要大
            //故要想等于target,则需right--,然后继续判断
            if(price[left] + price[right] > target)
            {
                --right;
            }
            else if(price[left] + price[right] < target)
            {
            //由于是升序,如果左右指针指向的数,比目标数要小
            //故要想等于target,则需left--,然后继续判断
                ++left;
            }
            else
            {
            //由左右指针指向的数等于target,
            //保存两数,退出循环。
                res.push_back(price[left]);
                res.push_back(price[right]);
                break;
            }
        }
        return res;
    }
};

 

007 三数之和

1 题目描述

在这里插入图片描述
题目链接

2 思路

在这里插入图片描述

3 代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        vector<vector<int>> ret;
        //1、排序
        sort(nums.begin(),nums.end());
        
        //利用双指针解决问题
        int n = nums.size();
        
        //其实这里最合理的是i < n-1, 等于n -1 时不用判断了,因为left与right指向同一个数,而题目要求三数要不同
        //这里i < n 也没有问题,后续会处理i = n - 1的情况。
        for(int i = 0; i < n; ) //遍历固定数
        {
            //小优化,如果我们固定数nums[i] > 0,由于这为一个升序的的vector
            //故在固定数后续区间[left, right]区间内肯定找不到两个数的和等于nums[i]
            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
                {
                    //如果相等sum = target,则说明left与right指针所指向的数满足三元组的要求
                    ret.push_back({nums[i], nums[left], nums[right]});
                    ++left;
                    --right;

                    //去重,以及防止去重的过程中发生left、right发生越界
                    while(left < right && nums[left] == nums[left - 1]) ++left;
                    while(right > left && nums[right] == nums[right + 1]) --right;

                }
            }

            //去重i
            ++i;  //下一个固定数
            while(i < n && nums[i] == nums[i - 1])
            {
                ++i;
            }            
        }
        return ret;
    }
};

 

008 四数之和

1 题目描述

在这里插入图片描述
题目链接

2 思路

在这里插入图片描述

3 代码

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {

        vector<vector<int>> ret;

        //1、排序
        sort(nums.begin(), nums.end());

        //2、依次固定两个数,双指针解决问题O(n^3)
        int n = nums.size();
        for(int i = 0; i < n - 3;) // 固定第一个数
        {       
            for(int j = i + 1; j < n - 2; ) //固定第二个数
            {
                //利用双指针解决问题
                int left = j + 1;
                int right = n - 1;
                long long k = (long long)target - nums[i] - nums[j]; //如果k为int类型,可能会发生数据溢出

                while(left < right)
                {
                    int sum = nums[left] + nums[right];
                    if(sum < k) ++left;
                    else if(sum > k) --right;
                    else
                    {
                        //当sum和target值相等时,说明找到了符合要求的四数之和,
                        //继续判断
                        ret.push_back({nums[i], nums[j], nums[left], nums[right]});
                        ++left;
                        --right;

                        //去重,以及避免left,right越界
                        while(left < right && nums[left] == nums[left - 1]) ++left;
                        while(right > left && nums[right] == nums[right + 1]) --right;
                    }
                }
                //去重j,以及避免j越界
                ++j;
                while(j < n - 2 && nums[j] == nums[j - 1]) ++j;
            }
            //去重i,以及避免i越界
            ++i;
            while(i < n -3 && nums[i] == nums[i - 1]) ++i;
        }
        return ret;
    }
};

 

总结

在这里插入图片描述

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值