Leetcode15. 三数之和 (排序+双指针优化解法)步骤详解
创始人
2025-05-30 14:07:48
0

题目描述

给你一个整数数组 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 。

提示:

3 <= nums.length <= 3000
-105 <= nums[i] <= 105

题目地址

Leetcode 15. 三数之和

解题思路

1.暴力三循环

  第一种方法也是我们能够快速想出来的方法,即使用三个指针i、j、k分别指向三个数,进行遍历,遍历完进行去重操作即可,这里不做过多赘述,主要以第二种方法为主。

2.固定指针+双循环指针

  我们使用一个固定指针k,指向数组的开头,使其不断自增,小于nums.length - 2,这里需要小于 nums.length - 2,是因为需要保证其指针后最少有一个i指针和j指针的存在。
  随后我们使i指针指向k指针的后面一个位置,j指针指向数组末尾。

  判断sum = nums[k] + nums[i] + nums[j] 三者的和:

  • sum == 0:
      这时nums[k],nums[i],nums[j]三个数即为我们所求的三个数,将其插入返回链表中,并且使得i++和j–。

  这里需要说明一下的是,对两个指针的操作是同时的,简单说一下原因:
  在k不变的情况下,三者之和为0,那么当i++单独执行后,且不与之前的值重复,则更新后的三者必不可能为0,必大于0,此时则需要将 j–;
  反之,若仅仅更新j–,则三者之和必小于0,则下一步必然是更新i++。
  综上两种情况,无论我们怎么变化,都是需要同时变更两个指针,即该操作是需要将两者同时进行更新的,仅仅变更一个指针的话,在下一个循环内会变更另外一个指针,则会多循环一次。

  • sum < 0:
    三者之和 < 0,则说明值太小了,需要将小一点的数变大,仅有i++可以实现。
  • sum > 0:
    三者之和 > 0,则说明值太大了,需要将大一点的数变小,仅有j–可以实现。

代码示例

class Solution {public List> threeSum(int[] nums) {Arrays.sort(nums);List> ret = new LinkedList<>();// 这里让k < nums.length - 2 ,是保证k在i和j之前。for (int k = 0; k < nums.length - 2; k++) {if (nums[k] > 0) {// 如果连最小的数都是 > 0 ,那么后面的数都是比他大的数,则相加之后必为一个 > 0 的数break;}if (k > 0 && nums[k] == nums[k - 1]) {continue;}int i = k + 1;int j = nums.length - 1;while (i < j) {// nums[i] == nums[i - 1]时,直接跳过即可,因为结果和nums[i - 1]一致if (i >= k + 2) {if (nums[i] == nums[i - 1]) {i++;continue;}}// nums[j] == nums[j + 1]时,直接跳过即可,因为结果和nums[j + 1]一致if (j < nums.length -1) {if (nums[j] == nums[j + 1]) {j--;continue;}}// 判断三者之和是否为0if (nums[k] + nums[i] + nums[j] == 0) {List list = new LinkedList<>();list.add(nums[k]);list.add(nums[i]);list.add(nums[j]);ret.add(list);// 这里将i和j都进行更新i++;j--;} else if (nums[k] + nums[i] + nums[j] > 0) {j--;} else {i++;}}}return ret;}
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...