算法1--双指针

双指针

这里的指针不应仅仅理解为指针,其也可以是数组下标,还可以直接是数据本身,只要其可以在当前唯一找到对应数据。其一般用于对线性存储的数据(如数组)或数据读取时具有线性的问题进行求解,常见的双指针有2种形式:对撞指针和快慢指针,其中快慢指针一般用于出现循环的问题中。

经典例题

移动零

采用2个下标pos1=0和pos2=0,pos1指针不动,pos2指针向后遍历,遇到0就跳过,遇到非零元素就交换pos1和pos2下标的元素,同时++pos1。

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

复写零

找到最后会被移动到数组末尾的元素的下标pos1,同时令pos2指向数组末尾元素,pos1从后往前遍历数组,遇到非零元素直接将该元素拷贝到pos2位置,同时–pos2,如果pos1遇到0,就将2个零写到pos2当前其前一个位置上,同时pos2减2.

class Solution {
public:
    void duplicateZeros(vector<int>& arr) 
    {
    	//寻找最后会被移动到数组末尾的元素的下标
        int left=-1;
        int right=-1;
        while(right+1<arr.size())
        {
            ++left;
            ++right;
            if(0==arr[left])
            {
                ++right;
            }
        }
        if(right+1>arr.size())
        {
            arr[--right]=0;
            --left;
            --right;
        }
		
		//遍历数组进行复写
        while(left>=0)
        {
            if(0==arr[left])
            {
                arr[right--]=0;
            }
            swap(arr[left--],arr[right--]);
        }
    }
};

快乐数

由于给定一个int型数字,其各位的平方和一定有一个最大值(不会超过int最大值,可以自己验证)和一个最小值0,即数字的各位的平方和得到的数据的个数是有限的,如果我们不停的将数字的各位进行平方和操作,其一定会出现2个相同的数据,即对数据的平方和操作一定是存在循环的,因此可以使用快慢指针解决问题

class Solution {
public:
    int DestructNum(int num)
    {
        int ret=0;
        while(num)
        {
            ret+=(num%10)*(num%10);
            num/=10;
        }

        return ret;
    }

    bool isHappy(int n) 
    {
        int slow=n;
        int fast=n;
        do
        {
            slow=DestructNum(slow);
            fast=DestructNum(fast);
            fast=DestructNum(fast);
        }
        while(fast!=slow&&slow!=1);
        if(1==slow)
        {
            return true;
        }

        return false;
    }
};

盛水最多的容器

left指向数组第一个元素,right指向数组末尾元素,计算得到一个容积v1,假设当前left是left和right中组数数据较小的下标。
如果固定left不动,让right–:①right对应的数组的值大于等于right之前的值,由于容器的容积取决于短边left,此时容器的宽度又减少了,故得到的容积一定比v1小;②如果right对应的数组的值小于right之前的值,容器的宽度和高度都减小了,故容器容器也一定比v1小。综上,让较大边right移动,其得到的容积一定比v1小。
因此我们应该移动小边left和right中的较小边,直至left和right相撞,过程中得到的容积一一比较即可得到最大容积。

class Solution {
public:
    int maxArea(vector<int>& height) 
    {
        int max_capacity=0;
        int left=0;
        int right=height.size()-1;
        while(left<right)
        {
            int min_height=height[left];
            if(min_height>height[right])
            {
                min_height=height[right];
            }
            int cur_capacity=min_height*(right-left);
            if(max_capacity<cur_capacity)
            {
                max_capacity=cur_capacity;
            }
            if(height[left]<height[right])
            {
                ++left;
            }
            else
            {
                --right;
            }
        }

        return max_capacity;
    }
};

有效三角形个数

将数据进行排序,使数据具有单调性,采用定一移二,将最大边pos3指向组数末尾,边pos1=0,边pos2=pos3-1。
如果arr[pos1]+arr[pos2]>arr[pos3],那么pos1右边的元素加上arr[pos2]一定大于arr[pos3],此时可以直接计算出当前可以获得的三角形的个数,接着–pos2
如果arr[pos1]+arr[pos2]<=arr[pos3],那么pos2左边的元素加上arr[pos1]一定小于等于arr[pos3],无法构成三角形,此时++pos1

直至pos1和pos2直至相撞,再–pos3,重复以上操作直至pos3<2

class Solution {
public:
    int triangleNumber(vector<int>& nums) 
    {
        int count=0;
        sort(nums.begin(),nums.end());
        int max_side=nums.size()-1;
        for(;max_side>1;--max_side)
        {
            int side1=0;
            int side2=max_side-1;
            while(side1<side2)
            {
                if(nums[side1]+nums[side2]>nums[max_side])
                {
                    count+=side2-side1;
                    --side2;
                }
                else
                {
                    ++side1;
                }
            }
        }

        return count;
    }
};

和为目标值的两个数

对数组排序使数据单调,left=0,right指向数组末尾,
如果price[left]+price[right]>target,那么left右边的元素加上price[right]也一定大于target,故此时只要–right即可
如果price[left]+price[right]<target,那么right左边的元素加上price[left]也一定小于target,故此时只要++left即可

class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) 
    {
        int left=0;
        int right=price.size()-1;
        vector<int> ret;
        while(left<right)
        {
            int sum=price[left]+price[right];
            if(sum==target)
            {
                ret.push_back(price[left]);
                ret.push_back(price[right]);
                break;
            }
            else if(sum<target)
            {
                ++left;
            }
            else
            {
                --right;
            }
        }

        return ret;
    }
};

三数之和

对数组排序,接着定一移二,对于pos1和pos2的移动参照前一题

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums)
    {
       vector<vector<int>> ret;
       sort(nums.begin(),nums.end());
       int pos3=nums.size()-1;
       while(pos3>1)
        {
            int pos1=0;
            int pos2=pos3-1;
            vector<int> tmp;
            while(pos1<pos2)
            {
                int sum=nums[pos1]+nums[pos2]+nums[pos3];
                if(0==sum)
                {
                    tmp.push_back(nums[pos1]);
                    tmp.push_back(nums[pos2]);
                    tmp.push_back(nums[pos3]);
                    ret.push_back(tmp);
                    tmp.clear();
                    ++pos1;
                    while(pos1<pos2&&nums[pos1-1]==nums[pos1])
                    {
                        ++pos1;
                    }
                }
                else if(sum>0)
                {
                    --pos2;
                }
                else
                {
                    ++pos1;
                }
            }
            --pos3;
            while(pos3>1&&nums[pos3]==nums[pos3+1])
            {
                --pos3;
            }
        }

        return ret;
    }
};

四数之和

对数组排序,接着定二移二,对于pos1和pos2的移动参照前2题

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        sort(nums.begin(),nums.end());
        int pos4=nums.size()-1;
        vector<vector<int>> vv;
        while(pos4>2)
        {
            int pos3=pos4-1;
            while(pos3>1)
            {
                int pos2=pos3-1;
                int pos1=0;
                while(pos1<pos2)
                {
                    if(pos1<pos2)
                    {
                        //溢出处理
                        int sum=nums[pos1];
                        vector<int> tmp={nums[pos2],nums[pos3],nums[pos4]};
                        int i=0;
                        int flag=0;
                        while(i<3)
                        {
                            if(sum>=0)
                            {
                                if(tmp[i]>0&&INT_MAX-sum<tmp[i])
                                {
                                    --pos2;
                                    flag=1;
                                    break;
                                }
                                sum+=tmp[i];
                            }
                            else
                            {
                                if(tmp[i]<0&&INT_MIN-sum>tmp[i])
                                {
                                    ++pos1;
                                    flag=1;
                                    break;
                                }
                                sum+=tmp[i];
                            }
                            ++i;
                        }
                        if(flag)
                        {
                            continue;
                        }

                        if(sum==target)
                        {
                            vector<int> v={nums[pos1],nums[pos2],nums[pos3],nums[pos4]};
                            vv.push_back(v);
                            --pos2;
                            while(pos2>0&&nums[pos2]==nums[pos2+1])
                            {
                                --pos2;
                            }
                        }
                        else if(sum>target)
                        {
                            --pos2;
                        }
                        else
                        {
                            ++pos1;
                        }
                    }
                }
                --pos3;
                while(pos3>0&&nums[pos3]==nums[pos3+1])
                {
                    --pos3;
                }
            }
            --pos4;
            while(pos4>=0&&nums[pos4]==nums[pos4+1])
            {
                --pos4;
            }
        }

        return vv;
    }
};

相关推荐

  1. 算法1--指针

    2024-07-23 05:48:02       14 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-23 05:48:02       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-23 05:48:02       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-23 05:48:02       45 阅读
  4. Python语言-面向对象

    2024-07-23 05:48:02       55 阅读

热门阅读

  1. C++实现排序算法

    2024-07-23 05:48:02       14 阅读
  2. 微信小程序面试题汇总

    2024-07-23 05:48:02       14 阅读
  3. Ubuntu22.04重置root密码

    2024-07-23 05:48:02       16 阅读
  4. 手写简易版Spring IOC容器05【学习】

    2024-07-23 05:48:02       14 阅读
  5. 速盾:cdn技术实现原理是什么?

    2024-07-23 05:48:02       16 阅读
  6. Windows通过命令查看mac : getmac

    2024-07-23 05:48:02       17 阅读
  7. CentOS搭建 Mono 开发环境

    2024-07-23 05:48:02       13 阅读
  8. MVC(Model-View-Controller)架构简介

    2024-07-23 05:48:02       16 阅读
  9. 科普文:重读并翻译分布式计算经典文论-MapReduce

    2024-07-23 05:48:02       13 阅读
  10. Apache Commons技术详解

    2024-07-23 05:48:02       18 阅读