LeetCode 1. 两数之和
1. 暴力枚举
这道题需要在数组中找到两个不同位置的元素,使它们的和等于给定的目标值 target,并返回这两个元素的索引。
最容易想到的方法就是暴力枚举。
使用两层 for 循环,依次检查数组中所有可能的数对。如果两个元素的和恰好等于 target,就返回它们对应的索引。
为了避免重复枚举,也为了保证不会使用同一个元素两次,内层循环可以直接从 i + 1 开始。
Python 代码:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
n=len(nums)
for i in range(n):
for j in range(i+1,n):
if nums[i]+nums[j]==target:
return [i,j] C++ 代码:
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 vector<int>{i, j};
}
}
}
return vector<int>();
}
};这种方法理解起来很简单,但双层循环的时间复杂度为 。
当数组长度增加时,需要检查的数对也会迅速增多。那么,有没有办法避免逐个枚举所有数对呢?
2. 哈希表优化
换个角度思考。
我们需要找到两个数 x 和 y,满足:
移项之后,可以得到:
也就是说,当我们遍历到一个数 x 时,其实已经知道另一个数应该是多少了。
现在的问题就从“寻找两个数”,变成了“寻找一个确定的数”。
不过,如果每次都重新遍历数组寻找 y,仍然会产生大量重复查找。
这里可以使用哈希表来优化。
哈希表能够根据键快速查找对应的值,因此我们可以将已经遍历过的元素保存起来:
- 键(Key):元素的数值。
- 值(Value):元素在数组中的索引。
遍历数组时,先计算当前元素需要匹配的另一个数:
y = target - nums[i]
接着检查哈希表中是否已经存在 y。
如果存在,说明之前遍历过一个能够与当前元素组成目标值的数,直接返回两者的索引即可。
如果不存在,就把当前元素及其索引存入哈希表,继续遍历。
这样,每个元素只需要处理一次,不必反复扫描整个数组。
Python 代码:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
n=len(nums)
hs=dict()
for i in range(n):
y=target-nums[i]
if y in hs:
return [i,hs[y]]
hs[nums[i]]=iC++ 代码:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hs;
for (int i = 0; i < nums.size(); i++) {
int y = target - nums[i];
if (hs.count(y))
return vector<int>{i, hs[y]};
hs[nums[i]] = i;
}
return vector<int>{};
}
};这里有一个值得注意的细节:为什么要先查询哈希表,再将当前元素存进去?
因为题目要求使用两个不同位置的元素。如果先插入再查询,就有可能把当前元素与它自己匹配。
例如,数组为 [3, 3],目标值为 6。
遍历第一个 3 时,哈希表中还没有需要的 3,于是将它和索引 0 存进去。
遍历第二个 3 时,就能找到之前保存的元素,返回两个不同的索引。
因此,先查询、后插入的顺序不能随意颠倒。
3. 复杂度分析
对比两种方法:
| 解法 | 时间复杂度 | 额外空间复杂度 |
|---|---|---|
| 暴力枚举 | ||
| 哈希表 | 平均 |
暴力枚举不需要额外的数据结构,但最坏情况下需要检查 个数对。
哈希表则用额外的空间保存已经遍历过的元素。在哈希查询和插入平均为 的情况下,只需遍历一次数组,整体时间复杂度就能降到 。
这道题的关键在于:利用 target - x 确定需要查找的数,再通过哈希表避免重复遍历。
相比直接枚举所有数对,这种方法用额外的存储空间换来了更高的平均查询效率。
聊两句
评论审核后显示有疑问、补充,或者想交流一下,都可以写在这里。
评论区将在滚动到这里时加载。