1.题目描述
原题链接:Two Sum
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, and you may not use the same element twice.(可以假设这组数有且只有一个答案,而且返回的下标不能相同)
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
然后完善下面的代码:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
}
}
2.解题思路
解法1
最简单的暴力破解,直接用两层遍历求出所有数组项两两相加之和,然后与目标值比较,但算法复杂度最高,经两层遍历后达到O(n2):
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (unsigned int i = 0; i < nums.size(); ++i)
for (unsigned int j = 0; j < nums.size(); ++j)
if (nums[i] + nums[j] == target && i != j)
return vector<int>({i, j});
return vector<int>();
}
}
解法2
把nums数组的值与下标用结构体类型绑定起来,耗时n。
然后将这些结构体按值从小到大排序,用C++的sort方法,耗时nlog2n。
之后再创建两个指针指向排好序的结构体数组的两边,将它们对应的项的值加起来,如果小于target,则将指向数组开始的指针右移一个单位,否则令另一个指针左移一个单位,然后重新比较两数之和以及目标值,不断重复这个过程。
由于必然有两个数值,一大一小,它们的和为目标值,所以不断趋近后可以得到这两个数对应的结构体,得到它们的下标,这个过程要耗时n。
所以总耗时为2n+nlog2n,即为O(nlogn)。
class Solution {
private:
struct smg{
int num;
int index;
smg(int n, int i):num(n),index(i){}
};
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<smg> smgs;
for(unsigned int i = 0; i < nums.size(); i++)
smgs.push_back(smg(nums.at(i), i));
sort(smgs.begin(), smgs.end(), [](smg s1, smg s2)->bool{
return s1.num < s2.num;
});
int start = 0, end = smgs.size() - 1;
while(start < end) {
int result = smgs[start].num + smgs[end].num;
if(result < target)
start++;
else if(result > target)
end--;
else
break;
}
return vector<int>({smgs[start].index, smgs[end].index});
}
}
解法3
hash的查找是通过一个从key到value的运算函数来实现的,算法与数据量无关,所以认为是O(1)的。
可以利用hash的这个特殊性来实现O(n)的算法,而刚好unordered_map的底层是一个防冗余的哈希表(采用除留余数法):
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> m;
for (unsigned int i = 0; i < nums.size(); ++i) {
if (m.count(target - nums[i]))
return vector<int>({i, m[target - nums[i]]});
m[nums[i]] = i;
}
return vector<int>();
}
}
3.疑问
上面三种方法理论上时间复杂度应该是O(n2)、O(nlogn)、O(n)的,但是我在leetcode上面提交后时间却是196ms、4ms、8ms。这显然是超出预料的,是因为数据量还是不够大,无法忽视其他因素吗,还是其他什么原因呢?如果有知道的朋友请在下面留言。