1. 算法精讲背景与价值
两数之和与三数之和是算法领域最经典的入门题型,也是大厂面试中的高频考点。我在刷LeetCode时发现,很多初学者虽然能勉强通过暴力解法AC,但对哈希表优化、双指针技巧等核心思想理解不深。这就像只会用蛮力拆门,却不知道钥匙就挂在腰间。
以Python3为例,两数之和的最优解法时间复杂度可以降到O(n),而三数之和通过排序+双指针能达到O(n²)。掌握这些算法不仅能通过面试,更能培养计算机思维——就像数学家眼中的"美感",程序员也需要培养对时间/空间复杂度的敏感度。
2. 两数之和的三种解法对比
2.1 暴力枚举法
python复制def twoSum(nums, target):
for i in range(len(nums)):
for j in range(i+1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
这是最直观的解法,但时间复杂度O(n²)在数据量大时性能堪忧。就像在超市找两个人凑单满减,你挨个问遍所有顾客组合,效率自然低下。
2.2 哈希表缓存法
python复制def twoSum(nums, target):
hashmap = {}
for i, num in enumerate(nums):
complement = target - num
if complement in hashmap:
return [hashmap[complement], i]
hashmap[num] = i
这里用空间换时间,通过哈希表存储遍历过的数值及其索引。就像记下每个顾客的购物金额,遇到新顾客时直接查表看是否有匹配的"另一半"。
注意:Python中字典的key冲突处理会影响性能,建议测试时用不同规模的数据验证
2.3 排序双指针法
虽然两数之和用哈希表最优,但为过渡到三数之和,我们先看排序后的解法:
python复制def twoSum(nums, target):
nums_sorted = sorted(nums)
left, right = 0, len(nums)-1
while left < right:
current = nums_sorted[left] + nums_sorted[right]
if current == target:
return [left, right]
elif current < target:
left += 1
else:
right -= 1
这种方法需要额外处理原始索引的问题,但为后续的三数之和埋下伏笔。
3. 三数之和的进阶解法
3.1 问题转化思路
三数之和可以转化为"固定一个数,找另外两个数的和等于它的相反数"。就像餐厅三人拼桌,先确定一个人的预算,再找两人组合满足剩余金额。
3.2 完整代码实现
python复制def threeSum(nums):
nums.sort()
res = []
for i in range(len(nums)-2):
if i > 0 and nums[i] == nums[i-1]:
continue
left, right = i+1, len(nums)-1
while left < right:
s = nums[i] + nums[left] + nums[right]
if s < 0:
left += 1
elif s > 0:
right -= 1
else:
res.append([nums[i], nums[left], nums[right]])
while left < right and nums[left] == nums[left+1]:
left += 1
while left < right and nums[right] == nums[right-1]:
right -= 1
left += 1
right -= 1
return res
3.3 关键点解析
- 排序预处理:时间复杂度O(nlogn),但为后续双指针扫除障碍
- 去重处理:跳过连续相同元素避免重复解
- 指针移动:根据当前和与0的关系动态调整指针
4. 算法优化与边界处理
4.1 剪枝优化技巧
当nums[i] > 0时可以直接终止循环,因为排序后后面的数都更大:
python复制if nums[i] > 0:
break
4.2 特殊测试用例
需要特别注意以下case:
- 全零数组:[0,0,0,0]
- 包含重复元素:[-1,0,1,2,-1,-4]
- 无解数组:[1,2,3]
4.3 复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 排序 | O(nlogn) | O(1) |
| 双指针遍历 | O(n²) | O(1) |
| 总复杂度 | O(n²) | O(1) |
5. 实战中的常见误区
5.1 哈希表误用
尝试用哈希表直接解三数之和会导致:
- 去重逻辑复杂
- 需要额外存储二维索引
- 空间复杂度飙升
5.2 指针移动错误
忘记处理找到解后的指针移动:
python复制# 错误示范
if s == 0:
res.append(...)
# 缺少left/right的后续移动
5.3 变量命名陷阱
使用无意义的变量名如a/b/c会降低代码可读性,建议用left/right等语义化命名。
6. 扩展训练建议
- 四数之和:在三数之和基础上再加一层循环
- 最接近的三数之和:记录最小差值而非精确匹配
- 两数之和II-输入有序数组:直接使用双指针法
我建议按这个顺序刷题:
- 两数之和 → 两数之和II → 三数之和 → 最接近的三数之和 → 四数之和
每次写完代码后,试着在白板上模拟运行过程。就像下棋复盘,这种可视化训练能加深对指针移动的理解。我在面试候选人时,最看重的不是背题能力,而是能否清晰解释每个决策背后的计算逻辑。