Leetcode 第 1 题(Two Sum)

来源:互联网 发布:php自助建站系统源码 编辑:程序博客网 时间:2024/06/05 20:58

Leetcode 第 1 题

昨天去逛了逛这个网站,感觉挺有意思。准备有空的时候就做一两道。

第一道题目是这样的:

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

UPDATE (2016/2/13):
The return format had been changed to zero-based indices. Please read the above updated description carefully.

这个题目相对来说很简单。最直接的做法是遍历这个数组中的任意两个元素。计算他们的和是否满足要求。下面贴一个最原始,最粗暴的解法:

class Solution {    public:    vector<int> twoSum(vector<int> &nums, int target)     {        vector<int> result;        int N = nums.size();        for (int i = 0; i < N - 1; i++)         {            for (int j = i+1; j < N; j++)             {                if (numbers[i] + numbers[j] == target)                 {                    result.push_back(i+1);                    result.push_back(j+1);                    return result;                }            }        }        return result;    }};

两重循环,算法的时间复杂度为 O(n2)。 在这个算法的框架下,唯一可以优化的地方在于那条判断语句:

nums[i] + nums[j] == target

每次判断时都要重新计算一下两个元素的和。实际上这步求和计算可以剩下来。下面是改进后的代码:

class Solution {    public:        vector<int> twoSum(vector<int>& nums, int target) {            vector<int> ret;            int N = nums.size();            for(int i = 0; i < N-1; i++)            {                int val = target - nums[i];                for(int j = i+1; j < N; j++)                {                    if(nums[j] == val)                    {                        ret.push_back(i);                        ret.push_back(j);                        return ret;                    }                }            }        }    };

这样改进之后,运算速度大约可以提高 30%。

不过还是挺慢的。理论上来说,遍历一遍这个数组就能获得全部信息了。没有必要反复的遍历这么多次。

举个例子:

Given nums = [2, 7, 11, 15], target = 9

含显然,[2, 7, 11, 15] 与它配对的数组是 [7, 2, -2, -6]。 这个数组是可以提前算出来的。之后我们只要在这个数组里查找有没有我们需要的数字就好了。选择好合适的数据结构,这个查找的工作的时间复杂度可以做到O(1)这么低。

class Solution {public:    vector<int> twoSum(vector<int>& nums, int target) {        map<int, int> lookup;        int N = nums.size();        for(int i = 0; i < N; i++)        {            lookup.insert(pair<int, int>(nums[i], i));        }        for(int i = 0; i < N; i++)        {            int value = target - nums[i];            if(lookup.count(value) && lookup[value] != i)            {                vector<int> ret;                ret.push_back(i);                ret.push_back(lookup[value]);                return ret;            }        }    }};

改成这个代码之后运行速度提高了一个数量级。但是也只是打败了27.73% 的代码提交者。所以还是有改进的余地。

想一想,这个代码可以改进的地方也就是这两个循环了。现在第一个循环用来建立map。第二个循环使用这个 map。 其实用一个循环就可以。因为答案由两个数组成,当我们的map 数据不全时,可能会错过一次配对,但是肯定不会错过第二次配对的。按照这个思路,代码进一步修改为:

class Solution {public:    vector<int> twoSum(vector<int>& nums, int target) {        map<int, int> lookup;        int N = nums.size();        for(int i = 0; i < N; i++)        {            int value = nums[i];            if( lookup.count(target - value) )            {                vector<int> ret;                ret.push_back(lookup[target - value]);                ret.push_back(i);                return ret;            }            lookup.insert(pair<int, int>(value, i));        }    }};

现在这个代码已经可以打败 45% 的答题者了。剩下的可以优化的地方已经不多了,折腾了一会儿,一直没能突破这个 45%。。。

各位大神们,求一个更好的代码。

1 0
原创粉丝点击