硅基俊宁.
Skills · 技能体系 ↗
← 返回文章

三数之和:排序与双指针

俊宁 · 日期未详
整理自原官网的历史学习笔记,保留原有译文、引用和署名,不把资料内容认作本人研究或实践成果。本篇有格式适配或明确勘误,详见官网迁移清单。
查看官网迁移清单
三数之和:排序与双指针封面

15. ⭐️​三数之和

题目描述 中等 数组 双指针 排序

给你一个整数数组 nums,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k,同时还满足 nums[i] + nums[j] + nums[k] == 0。请你返回所有和为 0 且不重复的三元组。

提示 答案中不可以包含重复的三元素。

示例 1:

输入:nums = [-1, 0, 1, 2, -1, -4]
输出:[[-1, -1, 2], [-1, 0, 1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0。
不同的三元组是 [-1, 0, 1] 和 [-1, -1, 2]

示例 2:

输入:nums = [0, 1 ,1]
输出:[]
解释:唯一可能的三元组和不为 0。

示例 3:

输入:nums = [0, 0, 0] 输出:[[0, 0, 0]] 解释:唯一可能的三元组和为 0。

提示:

思路

nSum 系列问题的核心思路就是排序+双指针。

先给数组从小到大排序,然后双指针 left 和 right 分别在数组开头和结尾,这样就可以控制 nums[left] 和 nums[right] 这个两数之和的大小:

如果你想让它俩的和大一些,就让 left++,如果你想让它俩的和小一些,就让 right--。

三数之和

基于两数之和可以得到一个万能函数 nSumTarget,扩展出 n 数之和的解法。

解法代码

画手大鹏解法 双指针

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
  let ans = [];
  const len = nums.length;
  if(nums == null || len < 3) {
    return ans;
  }
  nums.sort((a, b) => a - b); // 排序
  for (let i = 0; i < len ; i++) {
    if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
    if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
    let left = i + 1;
    let right = len - 1;
    while(left < right) {
      const sum = nums[i] + nums[left] + nums[right];
      if(sum == 0) {
        ans.push([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 if (sum > 0) {
        right--;
      }
    }
  }
  return ans;
};