双指针算法·两数之和·三数之和

简介: 双指针算法·两数之和·三数之和

如题目所示,这篇文章要讲解的三道题是有很大的关联的,循循渐进逐步展开,介绍双指针算法在解决这类题时能带来的优化。

两数之和

这道题比较简单,也是带入这种题型不错的选择,如题目所说,提供的数组已经是升序,使用暴力解法将所有的两数组合全部遍历一遍,这种解法的时间复杂度为O(N2),而且题目所提供的升序数组也没有用到,素以我们可以借助升序来寻找跟好的算法。

双指针你一定会想到,因为是升序,我们可以用两个指针left和right分别指向数组首位置和末位置,这样就可以知道最大元素和最小元素的和,如果和是大于目标值,就左移right,此时得到的目标值就会减小(因为是升序嘛),如果小于目标值,那就右移left,这样的道德目标值就会变大,这样只需要遍历一遍就可以债哦哦到结果。

以下是C++解法

vector<int> twoSum(vector<int>& price, int target) {
  int i=0,j=price.size()-1;
    vector<int> a;//偷懒了i->left j->right
    while(i!=j)
    {
        int sum=price[i]+price[j];
        if(sum<target)
        {
            i++;
        }
        if(sum>target)
        {
            j--;
        }
        if(sum==target)
        {
            break;
        }
    }
    a.push_back(price[i]);
    a.push_back(price[j]);
    return a;
}

三数之和

有了前一道题的衬托,我们就可以很轻松的想出这道题的解法,首先还是要介绍暴力解法,三层for循环,遍历出所有符合条件的三元组,但是这道题有很难搞的地方就是不可以包含重复的三元组,所以我们找出所有的三元组之后还需要进行去重操作。

先思考思考如何使用双指针算法思想进行解决,对于第一道题目,有着很重要的条件,那就是升序数组,我们可以找出规律从而简化以减少遍历次数,减小时间复杂度。

所以我们要先将数组排序,返回值类型为二维数组,我们提前构造一个二维数组作为返回值。

此时数组已经是一个升序数组了,我们的目标是找到三个数是他们的和等于0,换一种思路就是找到两个数,使他们的和等于第三个数的负数,这样就回归到两数之和了,首先我们要先锁定一个数,作为第三个数,在剩下的数中找到两个使它们的和等于锁定的数的负数即可,找两个数的操作和第一题的思路一模一样。

如何去重呢?

这是一个比较麻烦的问题。

在找到一组符合要求的值之后,判断left后边的和前边的值是否和已经记录过的相同,如果相同的话,那就跳过相同的数,就可以实现去重操作。不要忘记咯,我们选择的目标值也是要跳过相同的元素(就是目标值也是不同的),这样就切切实实实现了去重操作。

举例说明:

在锁定1之后,后边的1也要全部跳过,在left为-1right为0时,符合条件,但是为了去重,right要跳过所有的1,left要跳过所有的-1,即去重操作。要注意的是,在left前移和right后移的过程中,left保持恒小于right。

这道题目还要注意的点就是返回的对象为二维数组,在打印时可以使用两层for循环。

代码如下

class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums)
{
    vector<vector<int>> a;
    sort(nums.begin(), nums.end());
    int size = nums.size() - 1;
    for (int i = size; i >= 0; )
    {
        if (nums[i] < 0)
        {
            break;
        }
        int target = -nums[i];
        int right = i - 1;
        int left = 0;
        while (left < right)
        {
            if (nums[right] + nums[left] > target)right--;
            else if (nums[right] + nums[left] < target)left++;
            else {//此时我们找到了符合条件的值
                a.push_back({ nums[i],nums[right],nums[left] });//直接将这个三元组插入
                left++;
                right--;
                //去重操作
                while (left < right && nums[left] == nums[left - 1])left++;
                while (left < right && nums[right] == nums[right + 1])right--;
            }
        }
        i--;
        while (i > 0 && nums[i] == nums[i + 1])
        {
            i--;
        }
    }
    for (auto i : a)
    {
        for (auto s : i)
        {
            cout << s << ' ';
        }
        cout << endl;
    }
    return a;
}
};
目录
相关文章
|
5天前
|
算法
算法每日一题---两数之和
算法每日一题---两数之和
17 0
|
5天前
|
存储 算法 容器
算法:双指针
算法:双指针
13 3
|
5天前
|
存储 算法
Leetcode 30天高效刷数据结构和算法 Day1 两数之和 —— 无序数组
给定一个无序整数数组和目标值,找出数组中和为目标值的两个数的下标。要求不重复且可按任意顺序返回。示例:输入nums = [2,7,11,15], target = 9,输出[0,1]。暴力解法时间复杂度O(n²),优化解法利用哈希表实现,时间复杂度O(n)。
22 0
|
5天前
|
算法 前端开发 JavaScript
< 每日算法:一文带你认识 “ 双指针算法 ” >
`双指针`并非指的是一种具体的公式或者范式。而是一种运算思路,用于节省逻辑运算时间的`逻辑思路`!双指针算法通常用于`优化时间复杂度`!
< 每日算法:一文带你认识 “ 双指针算法 ” >
|
5天前
|
算法
优选算法|【双指针】|611.有效三角形的个数
优选算法|【双指针】|611.有效三角形的个数
|
5天前
|
算法
优选算法|【双指针】|202.快乐数
优选算法|【双指针】|202.快乐数
|
5天前
|
算法
优选算法|【双指针】283.移动零
优选算法|【双指针】283.移动零
|
5天前
|
算法
优选算法|【双指针】|1089.复写零
优选算法|【双指针】|1089.复写零
|
5天前
|
存储 算法
【优选算法专栏】专题九:链表--------两数之和
【优选算法专栏】专题九:链表--------两数之和
15 0