LeetCode算法练习之两数之和

题目位置:https://leetcode-cn.com/problems/two-sum/

刚刚接触算法的人一般看到这个题目就想到可以二次循环来莽穿,这样其实可以,我试了试居然也可以过。

这个算法的时间复杂度是O(n),分析一下计算步骤,我们会发现一个很大的问题:假设输入数据是

nums=[100,5,4,3,2,1,6] ,target=106,

循环开始时,nums[i]先取100,nums[j]取5,发现100+5小于106

再取nums[j]=4,这时我们发现问题,既然100+5就小于目标了,100+4以及后面的100+3,100+2就没有了判断的必要。

算法都是这样,针对具体问题,必须具体分析,才能找到优解

既然找答案与数字大小有关,可以考虑先进行排序

然后使用双指针法进行解题。简单介绍双指针方法,此算法在很多题目中均有广泛应用。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> cpnums=nums;
        vector<int> res;
        sort(cpnums.begin(), cpnums.end());
        int i=0;
        int j=nums.size()-1;
        while(i<j){
            if(cpnums[i]+cpnums[j]>target){
                j--;
            }
            else if(cpnums[i]+cpnums[j]<target){
                i++;
            }else{
                return res;
            }
        }
        return res;
    }
};

双指针法,记住左指针和右指针都是 只能往一个方向移动的  指针。这里左指针只能右移动,而右指针只能左移动。而且,两个指针移动  对于答案的影响是相反的  类似二分查找。(我感觉我应该单独再写一个blog说这个问题)

排序,一般都是使用快速排序或者归并排序,时间复杂度为O(ln n ),而双指针查找最多只遍历一遍数组,所以时间复杂度为O(n),合起来时间复杂度为O(ln n )

 

差不多就是这样,但是这个代码寻找的是所有的二元组,而不是i,j,因为在排序的过程中,数据的原始位置被打乱了,不能用排序来解,所以我没有在leetcode上提交。 

最后,有没有可以在O(n)时间复杂度内实现的解法?我们再来看题目,两个数,确定一个数之后找另一个相加=0的数,可以想到查找算法。而两个数对应键值对也让我们往那里想。此题使用散列表字典进行求解,就可以在O(n)的时间复杂度内实现。

散列表中,元素没有顺序,所以为解答此题,需要在字典结构(元素的“值”)中记录该元素原本在数组中的位置。元素的键则是该数的大小,因为同样的数字不会出现两次,而且找数的时候是按键来找的。

循环时,将元素加入到散列表中,同时算出和它相加=结果的数,再查找散列表中是否有这个数。因为散列表的查找可以在常数时间内完成,所以这三步都可以在常数时间内完成。 程序仅对数组进行一次遍历,时间复杂度为O(n)。

可以看到,虽然此算法时间上远超上一个,但是空间复杂度仅有12.18%,这是因为时间与空间不可兼得,一般采用像散列表这样用空间换时间的方式获得更好的算法。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值