【算法】双指针

双指针


    ~~~    双指针可以用来解决 子数组问题,不过通常来说,使用双指针通常需要对原数组进行sort排序。

Leetcode11 盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

//(双指针法)取巧——设置左右端点,只会向内移动:短板向内移动(长板向内移动不可能使得面积变大)
class Solution {
public:
    int maxArea(vector<int>& height) {
        int n=height.size();
        int s=min(height[0],height[n-1])*(n-1),max=0;
        int i=0,j=n-1;
        while(i<j)
        {
            s=min(height[i],height[j])*(j-i);
            if(max<s)
                max=s;
            if(height[i]>height[j])
                j--;
            else if(height[i]==height[j])
            {
                j--;
                i++;
            }
            else
                i++;
        }
        return max;
    }
};

Leetcode15 三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例1
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105

题解
三数之和,我们很容易得到思路是:确定两个数,遍历第三个数看是否nums[i]符合条件。我们可以用双指针来解决。有两种设置指针的思路。
【思路1】设置最左侧left,最右侧right,逐渐向内靠拢(常规)
在这里插入图片描述
【思路2】排序后循环遍历数组,第i次循环nums[i],设置left=i+1(nums[i]的左端),right=len-1(整个数组的最右端)。
nums[i]+nums[left]+nums[right] ==0 ? ①<0:L++ ②>0:R- - ③=0:L++ && R- -
双指针移动时注意重复元素即可。

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {
    vector<vector<int>> v;  
        int len=nums.size();
        if(len<=2)
            return v; 
        sort(nums.begin(),nums.end());
        int L,R;  //双指针
        for(int i=0;i<len;i++)
        {
            if(nums[i]>0)  
                break;
            L=i+1;  R=len-1;
            while(R>L)
            {
                if(nums[i]+nums[L]+nums[R]==0)
                {
                    v.push_back({nums[i],nums[L],nums[R]});
                    while(R>L && nums[L]==nums[L+1])
                        L++;
                    while(R>L && nums[R]==nums[R-1])
                        R--;
                    L++;
                    R--;
                }
                else if(nums[i]+nums[L]+nums[R]>0)
                    R--;
                else
                    L++;
            }
            while(i+1<len && nums[i]==nums[i+1])
                i++;
        }
        return v;
    }
};

Leetcode16 最接近的三数之和

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int len=nums.size();
        sort(nums.begin(),nums.end());
        int ans;
        for(int i=0;i<len;i++) 
        {
            int start = i+1, end = len - 1;
            while(start < end) 
            {
                int sum = nums[start] + nums[end] + nums[i];
                if(abs(target - sum) < abs(target - ans))
                    ans = sum;
                if(sum > target)
                    end--;
                else if(sum < target)
                    start++;
                else
                    return ans;
            }
        }
        return ans;
    }
};

Leetcode18 四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
         ~~~~~~~~          0 <= a, b, c, d < n
         ~~~~~~~~          a、b、c 和 d 互不相同
         ~~~~~~~~          nums[a] + nums[b] + nums[c] + nums[d] == target

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

提示:
1 <= nums.length <= 200
- 1 0 9 10^9 109 <= nums[i] <= 1 0 9 10^9 109
- 1 0 9 10^9 109 <= target <= 1 0 9 10^9 109

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector <int>> v;  //返回答案的二维数组
        sort(nums.begin(),nums.end());
        int len=nums.size();
        int left,right;  //双指针
        if(len<4)
            return v;
        for(int i=0;i<len-3;i++)
        {
            for(int j=i+1;j<len-2;j++)
            {
                int sum=nums[i]+nums[j];  //前两数之和
                left=j+1;  right=len-1;
                while(right>left)   
                {
                    long long x = static_cast<long long>(sum);
                    long long y = static_cast<long long>(nums[left]);
                    long long z = static_cast<long long>(nums[right]);
                    if(x+y+z>target)
                        right--;
                    else if(x+y+z<target)
                        left++;
                    else
                    {
                        v.push_back({nums[i],nums[j],nums[left],nums[right]});
                        while(right>left && nums[right]==nums[right-1])
                            right--;
                        while(right>left && nums[left]==nums[left+1])
                            left++;
                        right--;
                        left++;
                    }
                }
                while(j+3<len && nums[j]==nums[j+1])
                    j++;
            }
            while(i+4<len && nums[i]==nums[i+1])
                i++;
        }
        return v;
    }
};

Leetcode80 删除有序数组中的重复项 II

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。

//双指针————子数组问题要考虑双指针
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int len=nums.size();
        if(len<=2)
            return len;
        int slow=2,fast=2;
        while(fast<len)
        {
            if(nums[slow-2]==nums[fast])
            {
                fast++;
            }
            else
            {
                nums[slow]=nums[fast];
                slow++;
                fast++;
            }
        }
        return slow;
    }
};
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值