1. LeetCode数组题核心知识点解析(15/16题)
最近在刷LeetCode数组类题目时,发现第15题(三数之和)和第16题(最接近的三数之和)是非常典型的双指针应用场景。这两道题在各大公司的面试中出现频率极高,仅过去三个月就有超过20位学员反馈在字节、腾讯的面试中遇到过变形题。今天我就结合自己AC这两道题的实战经验,分享几个关键解题技巧和容易踩坑的细节。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三数之和问题深度拆解
2.1 问题本质与暴力解法
题目要求找出数组中所有不重复的三元组,使得三个数之和为0。最直观的暴力解法是三层循环遍历,时间复杂度O(n³)。但在LeetCode上这种解法必定超时,因为题目约束条件中n的规模可以达到3000。
关键观察点:当数组排序后,a + b + c = 0等价于b + c = -a,这就将三数之和转化为了两数之和问题
2.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
l, r = i+1, len(nums)-1
while l < r:
s = nums[i] + nums[l] + nums[r]
if s < 0:
l += 1
elif s > 0:
r -= 1
else:
res.append([nums[i], nums[l], nums[r]])
while l < r and nums[l] == nums[l+1]: # 左指针去重
l += 1
while l < r and nums[r] == nums[r-1]: # 右指针去重
r -= 1
l += 1
r -= 1
return res
2.3 三个易错点实录
-
去重逻辑:我在初期实现时经常漏掉内层循环的去重判断,导致输出包含重复三元组。必须在外层循环和内层指针移动时都做重复值判断。
-
边界条件:当输入数组包含3个0时,需要特殊处理。测试用例[0,0,0]是常见的边界case。
-
提前终止:当nums[i] > 0时可以直接break,因为排序后后面的数不可能使和为0。这个优化能让运行时间减少30%。
3. 最接近的三数之和进阶解法
3.1 问题变形与算法选择
第16题可以看作是15题的变种,要求找到和最接近target的三数之和。虽然同样可以用双指针,但需要调整判断逻辑:
python复制def threeSumClosest(nums, target):
nums.sort()
closest = float('inf')
for i in range(len(nums)-2):
l, r = i+1, len(nums)-1
while l < r:
current_sum = nums[i] + nums[l] + nums[r]
if abs(current_sum - target) < abs(closest - target):
closest = current_sum
if current_sum < target:
l += 1
elif current_sum > target:
r -= 1
else:
return target # 找到精确解直接返回
return closest
3.2 性能优化技巧
-
早期终止:当找到等于target的组合时立即返回,可以节省不必要的计算。
-
差值比较:使用绝对值比较来追踪最近接的值,比维护一个排序列表更高效。
-
指针移动策略:根据当前和与target的大小关系决定移动哪个指针,这与标准三数之和问题类似但判断条件不同。
4. 双指针法的通用模式
通过这两道题,我总结出双指针处理数组问题的通用模板:
-
排序预处理:几乎所有的双指针解法都需要先对数组排序(时间复杂度O(nlogn))
-
外层循环:固定一个元素作为基准(通常是第一个数)
-
内层双指针:
- 左指针初始化为外层索引+1
- 右指针初始化为数组末尾
- 根据比较结果决定移动哪个指针
-
去重处理:
- 外层循环跳过相同元素
- 内层找到解后跳过相同元素
5. 同类题型扩展训练
为了巩固双指针技巧,建议继续刷以下题目:
-
- 四数之和(双指针升级版)
-
- 较小的三数之和(变形题)
-
- 两数之和 II(基础版)
-
- 盛最多水的容器(经典双指针)
在实际面试中,面试官常常会要求手写三数之和的代码,然后基于此进行变形。比如最近美团的一道面试题:"如果要求三数之积等于某个值,该如何修改算法?" 这时候双指针的核心思想仍然适用,只是比较条件需要调整。
