1. 暴力
双重循环找到两数之和等于target的两个数。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
if(numbers.empty()) return {-1,-1};
for(int idx1 = 0; idx1 < numbers.size()-1; ++idx1){
for(int idx2 = idx1 + 1; idx2 < numbers.size(); ++idx2){
if(numbers[idx1] + numbers[idx2] == target) return {idx1+1, idx2+1};
}
}
return {-1,-1};
}
};
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
空间复杂度:
O
(
1
)
O(1)
O(1)
2. 哈希表
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
unordered_map<int, int> hash_num;//存储值和下标
for(int i = 0; i<numbers.size(); ++i){
hash_num[numbers[i]] = i;//数组元素作为键,下标作为值
}
for(int j=0; j<numbers.size(); ++j){
auto iter = hash_num.find(target - numbers[j]);//查找是否存在值为target - numbers[j]的元素
if(iter != hash_num.end()) return {j+1, iter->second + 1};
//或:if (hash_num.count(target - numbers[i]) > 0) return {hash_num[target - numbers[i]], i + 1};
}
return {-1, -1};
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
n
)
O(n)
O(n)
暴力解法和哈希表解法都没有利用数组有序这一条件。
3. 二分查找
由于数组是有序的,固定一个元素后,用二分查找搜索另一个元素的位置。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
if(numbers.empty()) return {-1, -1};
for(size_t idx1 = 0; idx1 < numbers.size()-1; ++idx1){
size_t l = idx1+1, r = numbers.size()-1;
while(l<=r){//等号忘了
size_t mid = l + ((r-l) >>1);//>>优先级小于+
if(numbers[mid] < target - numbers[idx1]) l = mid + 1;
else if(numbers[mid] > target - numbers[idx1]) r = mid - 1;
else return {(int)idx1+1, (int)mid+1};
}
}
return {-1, -1};
}
};
时间复杂度:
O
(
n
l
o
g
n
)
O(n \ log \ n)
O(n log n)
空间复杂度:
O
(
1
)
O(1)
O(1)
4. 双指针
难点在于理解指针的移动保证可以找到正确的解。假设正确的解为i、j。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
for(int i = 0, j = numbers.size()-1; i<j ; ){
int temp = numbers[i]+numbers[j];
if(temp > target) --j;
else if(temp < target) ++i;
else return {i+1, j+1};
}
return {-1,-1};
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)