1. 题目来源
链接:lc1. 两数之和
进阶:[M哈希] lc1711. 大餐计数(哈希+周赛222_2)
2. 题目解析
方法一:暴力
两层循环,枚举当前数和其他所有数是否能构成答案即可。同时有个简单的优化:不必枚举当前数前面的数,因为已经枚举过了。
时间复杂度: O ( n 2 ) O(n^2) O(n2)
代码:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); ++i)
for (int j = 0; j < nums.size(); ++j)
if (nums[i] + nums[j] == target && i != j) return {i, j};
return {};
}
};
// 暴力简单优化
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); ++i)
for (int j = i + 1; j < nums.size(); ++j)
if (nums[i] + nums[j] == target) return {i, j};
return {};
}
};
方法二:排序+二分
排序后,二分查找答案是否存在即可。
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
代码:
typedef pair<int, int> PII;
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<PII> tmp;
for (int i = 0; i < nums.size(); ++i) tmp.push_back({nums[i], i});
sort(tmp.begin(), tmp.end());
for (int i = 0; i < tmp.size(); ++i) {
int l = 0, r = tmp.size() - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (target - tmp[i].first >= tmp[mid].first) l = mid;
else r = mid - 1;
}
if (tmp[l].first + tmp[i].first == target && i != l) return {tmp[i].second, tmp[l].second};
}
return {};
}
};
// 整数二分的两种方式均可
typedef pair<int, int> PII;
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<PII> tmp;
for (int i = 0; i < nums.size(); ++i) tmp.push_back({nums[i], i});
sort(tmp.begin(), tmp.end());
for (int i = 0; i < tmp.size(); ++i) {
int l = 0, r = tmp.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (target - tmp[i].first <= tmp[mid].first) r = mid;
else l = mid + 1;
}
if (tmp[l].first + tmp[i].first == target && i != l) return {tmp[i].second, tmp[l].second};
}
return {};
}
};
func twoSum(nums []int, target int) []int {
type PII struct {
first int
second int
}
pair := make([]PII, len(nums))
for i, v := range nums {
pair[i].first = v
pair[i].second = i
}
sort.SliceStable(pair, func(i, j int) bool {
return pair[i].first < pair[j].first
})
for i := range pair {
l, r := 0, len(nums) - 1
for l < r {
mid := l + r
mid >>= 1
if (target - pair[i].first > pair[mid].first) {
l = mid + 1
} else {
r = mid
}
}
if pair[l].first + pair[i].first == target && i != l {
return []int{pair[i].second, pair[l].second}
}
}
return []int{}
}
方法三:排序+双指针
很清楚的思路,排序后具有单调性,双指针就可以处理了。
代码:
typedef pair<int, int> PII;
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<PII> tmp;
for (int i = 0; i < nums.size(); ++i) tmp.push_back({nums[i], i});
sort(tmp.begin(), tmp.end());
for (int i = 0, j = tmp.size() - 1; i < j; ) {
if (i < tmp.size() && j >= 0 && tmp[i].first + tmp[j].first > target) j --;
else if (i < tmp.size() && j >= 0 && tmp[i].first + tmp[j].first < target) i ++;
else return {tmp[i].second, tmp[j].second};
}
return {};
}
};
func twoSum(nums []int, target int) []int {
type PII struct {
first int
second int
}
pair := make([]PII, len(nums))
for i, v := range nums {
pair[i].first = v
pair[i].second = i
}
sort.SliceStable(pair, func(i, j int) bool {
return pair[i].first < pair[j].first
})
i, j := 0, len(nums) - 1
for ; i < len(nums); i ++ {
for i < j && pair[i].first + pair[j].first > target {
j --
}
if (i != j && pair[i].first + pair[j].first == target) {
return []int{pair[i].second, pair[j].second}
}
}
return []int{}
}
C++ 版本现在看起来还是写的有点冗余了,无非 > = < 三种情况,可以让 i 在 for 循环内部 ++ 即可。
方法四:哈希
顺序遍历数组元素,假设当前位置为 i
,查看从 [0, i - 1]
区间中是否可以和 nums[i]
构成答案。注意: 不要直接将 nums[i]
插入到哈希表中,这样会造成重复计算,即 区间变为 [0, i]
了,可能导致 nums[i]
自己被计算两次。
这里保证了答案存在且唯一,所有针对相同的 key
,我们直接将下标覆盖式的写入。其实细想也能发现:这个数组是不存在相同的 2 个以上元素,且答案还能恰好是其中两个之和的。这样我们需要返回的答案就有多个,我们对哈希表这样的覆盖式写入就是不满足要求的。且在 C++
中,若哈希表中 key
已经有了 value
值,若对其再次进行赋值操作,貌似改次操作会被丢弃掉。这是在评论区看简单,没做考证~
代码:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash;
for (int i = 0; i < nums.size(); ++i) {
if (hash.count(target - nums[i])) return {hash[target - nums[i]], i};
hash[nums[i]] = i;
}
return {};
}
};
func twoSum(nums []int, target int) []int {
m := map[int]int{}
for i, v := range nums {
if idx, ok := m[target - v]; ok {
return []int{idx, i}
}
m[v] = i
}
return []int{}
}