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%。。。
各位大神们,求一个更好的代码。