
本文详解 LeetCode 三数之和问题中双指针解法的常见错误——特别是因指针移动方向错误导致的 ArrayIndexOutOfBoundsException,并提供修复后的完整、健壮的 Java 实现。
本文详解 leetcode 三数之和问题中双指针解法的常见错误——特别是因指针移动方向错误导致的 `arrayindexoutofboundsexception`,并提供修复后的完整、健壮的 java 实现。
在使用双指针法求解 3Sum 问题时,核心思路是:先对数组排序,再固定一个数 nums[i],然后在剩余子数组 [i+1, n-1] 中用左右双指针 L 和 R 寻找满足 nums[L] + nums[R] == -nums[i] 的两数组合。该方法时间复杂度为 $O(n^2)$,空间复杂度为 $O(1)$(不计结果存储),是标准最优解。
然而,初学者常因一个细微笔误引发运行时异常。观察原始代码中的关键错误:
} else {
R += 1; // ❌ 错误!应向左收缩右指针
}当 nums[L] + nums[R] > target 时,说明当前和过大,需减小右值——即让 R 向左移动(R--),而非错误地 R++。R += 1 会导致 R 越界(例如 R = nums.length - 1 时再 ++,即访问 nums[nums.length]),直接触发 ArrayIndexOutOfBoundsException。
✅ 正确写法应为:
} else if (nums[L] + nums[R] < target) {
L++;
} else {
R--; // ✅ 向左收缩,确保 R 始终在有效范围内
}此外,还需注意以下关键细节以保证逻辑鲁棒性:
- 边界判断完整性:while (L < R) 是外层循环安全前提;内部跳过重复元素时,L < nums.length - 1 和 R > 0 防止越界;
- 去重逻辑位置:在找到一组解后,先跳过相邻重复值(while(L < ... && nums[L]==nums[L+1]) L++),再执行 L++ 和 R--,避免遗漏或重复;
- 循环范围严谨性:外层 i 最大取到 nums.length - 3(即 i <= nums.length - 3),确保 L = i+1 和 R = nums.length-1 构成至少两个元素的区间。
以下是修复后、经过验证的完整实现:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
int n = nums.length;
for (int i = 0; i <= n - 3; i++) {
// 跳过重复的固定元素,避免重复三元组
if (i > 0 && nums[i] == nums[i - 1]) continue;
int L = i + 1, R = n - 1;
int target = -nums[i];
while (L < R) {
int sum = nums[L] + nums[R];
if (sum == target) {
ans.add(Arrays.asList(nums[i], nums[L], nums[R]));
// 跳过左指针重复值
while (L < R && nums[L] == nums[L + 1]) L++;
// 跳过右指针重复值
while (L < R && nums[R] == nums[R - 1]) R--;
L++;
R--;
} else if (sum < target) {
L++;
} else {
R--; // 关键修复:必须递减,不可递增
}
}
}
return ans;
}
}? 总结与建议:
- 双指针移动方向必须与数值大小关系严格对应:和偏小 → 移动左指针增大值;和偏大 → 移动右指针减小值;
- 所有指针操作前务必校验索引有效性,尤其在 while 跳过重复时;
- 使用 Arrays.asList() 可简化临时列表创建;
- 提交前建议用 [-1,0,1,2,-1,-4] 等含重复元素的用例本地测试,验证去重与边界处理是否完备。
掌握这些要点,即可稳定、高效地通过 LeetCode 15. 3Sum。

















