Lintcode 56. 两数之和
题目描述:给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。
你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标。注意这里下标的范围是 0 到 n-1。
- 你可以假设只有一组答案。
这道题之在leetcode中也做过(【Leetcode热题100】Leetcode 1. 两数之和),当时用的是二分法,时间复杂度O(nlogn),空间复杂度O(n)。
这次用两根指针和哈希表方法再分别实现一下,关于这二者复杂度如下:
两根指针:时间复杂度O(nlogn),空间复杂度O(n);
哈希表:时间复杂度O(n),空间复杂度O(n);
这样看上去哈希表更好,这是因为本题是返回索引值,索引值需要额外空间O(n),如果是直接返回值的话,那二者的复杂度哈希表不变,而两根指针变为:时间复杂度O(nlogn),空间复杂度O(1),因为两根指针是直接在原数组中进行比较寻找的(所以无额外空间),此外它本身的时间复杂度是O(n),是因为需要先对数组排序(O(nlogn))导致复杂度为O(nlogn)。
下面给出两根指针和哈希表两种方法的实现代码:
// 1. 两根指针
class Solution {
public:
/**
* @param numbers: An array of Integer
* @param target: target = numbers[index1] + numbers[index2]
* @return: [index1 + 1, index2 + 1] (index1 < index2)
*/
vector<int> twoSum(vector<int> &numbers, int target) {
vector<int> result;
if (0 == numbers.size()) {
return result;
}
vector<int> sortIdx(numbers.size());
iota(sortIdx.begin(), sortIdx.end(), 0);//全部赋值为0
sort(sortIdx.begin(), sortIdx.end(), [&numbers](int i1, int i2) {return numbers[i1] < numbers[i2];});//获得原数组排序之后的索引
sort(numbers.begin(), numbers.end());//对原数组进行排序
int left = 0, right = numbers.size() - 1;
while (left < right) {
if (numbers[left] + numbers[right] == target) {
result.push_back(sortIdx[left] < sortIdx[right] ? sortIdx[left] : sortIdx[right]);
result.push_back(sortIdx[left] > sortIdx[right] ? sortIdx[left] : sortIdx[right]);
break;
} else if (numbers[left] + numbers[right] > target) {
right--;
} else {
left++;
}
}
return result;
}
};
// 2. 哈希表方法
class Solution {
public:
/**
* @param numbers: An array of Integer
* @param target: target = numbers[index1] + numbers[index2]
* @return: [index1 + 1, index2 + 1] (index1 < index2)
*/
vector<int> twoSum(vector<int> &numbers, int target) {
vector<int> result;
if (0 == numbers.size()) {
return result;
}
map<int, int> numsMap;//数值和索引的映射关系
for (int i = 0; i < numbers.size(); ++i) {
int other = target - numbers[i];
if (numsMap.count(other)) {
result.push_back(numsMap[other]);
result.push_back(i);
} else{
numsMap[numbers[i]] = i;
}
}
return result;
}
};