老姜讲技术

优秀是一种习惯!

--亚里士多德

老姜带你刷力扣系列-0001

老姜带你刷力扣系列-0001

原题:

  1. 两数之和(难度:简单)

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

  • 2 <= nums.length <= 104

  • -109 <= nums[i] <= 109

  • -109 <= target <= 109

  • 只会存在一个有效答案

进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?


分析:

第一题的难度还是相对比较简单的,从nums数组中找到相加等于target的两个数。 题目阅读理解并不复杂,首先来个暴力解法,双重for循环。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 准备返回结果的vector容器
        vector<int> res;
        for (int i=0;i<nums.size()-1;i++) {
            // 这里从i+1开始,限定n>=2,不会出错
            for (int j=i+1;j<nums.size();j++) {
                if (nums[i]+nums[j] == target) {
                    // 找到结果直接放入数据return
                    res.push_back(i);
                    res.push_back(j);
                    return res;
                }
            }
        }
        // 这里不return编译会报错,根据题目限定一定有答案,不会执行到这里
        // 实际工程中应该处理这种情况,报错或者返回特定的值给上游处理
        return res;
    }
};

提交看结果

执行用时: 416 ms , 在所有 C++ 提交中击败了 8.60% 的用户
内存消耗: 9.7 MB , 在所有 C++ 提交中击败了 96.95% 的用户

是不是很简单,就这?

当然没有这么简单,用时击败了不到10%的用户,仔细看题目的最后有个提示,可不可以有时间复杂度小于 O(n2) 的算法。

老姜出手必须有!

时间小于n2的,按照算法常识,可能的是n或者n*logn

我们先看nlogn,logn的算法一般就是二分查找了,如果需要二分查找,那么就必须有序, 排个序先,因为返回的数据是原始数据的下标,所以排序的同时,需要记录原始的下标,这就有点复杂, 理论上是可以实现的,但是内存占用应该会变大,我这里先不实现,大家可是自己尝试。

另外的可能性就是时间复杂度为n,也就意味着只遍历一遍或者有限次数。 比如示例2中,考虑如何在遍历到4的时候知道已经存在2,而且知道2的下标。 因为遍历的时间复杂度已经是O(n),这里到4找2的过程就必须是O(1)的。

这里当然不得不提HashMap,HashMap的查找时间为O(1),和待查找的数组的长度无关, 因为target是给定的,我们把2的角标存储到HashMap中,那么就可以实现O(1)的查找, 整体遍历是O(n),所以整体算法的时间复杂度是O(n),话不多说上代码!

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        std::map<int,int> index;
        vector<int> ret;
        for (int i=0;i<nums.size();i++) {
            int res = target - nums[i];
            auto it = index.find(res);
            if (it != index.end()) {
                    ret.push_back(it->second);
                    ret.push_back(i);
                    return ret;
            } else {
                index.insert(make_pair(nums[i], i));
            }
        }
        return ret;
    }
};

提交看结果

执行用时:8 ms, 在所有 C++ 提交中击败了 92.34% 的用户
内存消耗:10.7 MB, 在所有 C++ 提交中击败了 20.01% 的用户

时间提上去了,空间占用排位较低,这是算法里面典型的时间换空间,通过构造一个map来提升检索的速度。

你学废了吗?🐶