15. 三数之和
思路
要找出所有和为0且不重复的三元组,可以使用排序+双指针的策略:
-
排序数组:预处理数组,便于跳过重复元素和使用双指针
-
固定一个元素:遍历数组,固定当前元素
nums[i] -
双指针寻找匹配元素:
- 左指针
left = i + 1 - 右指针
right = nums.length - 1 - 计算
nums[i] + nums[left] + nums[right]的和
- 左指针
-
根据和调整指针:
- 和=0:找到有效三元组,记录结果并跳过重复元素
- 和<0:左指针右移(增加总和)
- 和>0:右指针左移(减小总和)
-
跳过重复元素:在每一步跳过重复值,避免重复三元组
复杂度分析
- 时间复杂度:O(n²)
排序 O(n log n) + 双指针扫描 O(n²) → 总体 O(n²) - 空间复杂度:O(1)
除结果集外,仅使用常数额外空间(排序占用 O(log n) 栈空间)
代码
import java.util.*;
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums); // 排序数组
for (int i = 0; i < nums.length - 2; i++) {
// 跳过重复的固定元素
if (i > 0 && nums[i] == nums[i - 1]) continue;
// 提前终止:最小元素已大于0
if (nums[i] > 0) break;
int left = i + 1, right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 跳过左侧重复元素
while (left < right && nums[left] == nums[left + 1]) left++;
// 跳过右侧重复元素
while (left < right && nums[right] == nums[right - 1]) right--;
// 移动到下一组不同元素
left++;
right--;
} else if (sum < 0) {
left++; // 需要更大的数
} else {
right--; // 需要更小的数
}
}
}
return result;
}
}

浙公网安备 33010602011771号