首页 > 其他分享 >LeetCode15. 三数之和

LeetCode15. 三数之和

时间:2023-03-22 10:34:08浏览次数:45  
标签:right nums int 三数 三元组 LeetCode15 left

题目描述:

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

思路:

这道题目使用双指针法 要比哈希法高效一些,动画效果如下:

 

拿这个nums数组来举例,首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。

依然还是在数组中找到 abc 使得a + b +c =0,我们这里相当于 a = nums[i],b = nums[left],c = nums[right]。

接下来如何移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。

如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。

时间复杂度:O(n^2)。

 

去重逻辑的思考

a的去重

说道去重,其实主要考虑三个数的去重。 a, b ,c, 对应的就是 nums[i],nums[left],nums[right]

a 如果重复了怎么办,a是nums里遍历的元素,那么应该直接跳过去。

但这里有一个问题,是判断 nums[i] 与 nums[i + 1]是否相同,还是判断 nums[i] 与 nums[i-1] 是否相同。

都是和 nums[i]进行比较,是比较它的前一个,还是比较他的后一个。

 

如果我们的写法是 这样:

if (nums[i] == nums[i + 1]) { // 去重操作
    continue;
}

那就我们就把 三元组中出现重复元素的情况直接pass掉了。 例如{-1, -1 ,2} 这组数据,当遍历到第一个-1 的时候,判断 下一个也是-1,那这组数据就pass了。

我们要做的是 不能有重复的三元组,但三元组内的元素是可以重复的!

所以这里是有两个重复的维度。

那么应该这么写:

if (i > 0 && nums[i] == nums[i - 1]) {
    continue;
}

这么写就是当前使用 nums[i],我们判断前一位是不是一样的元素,在看 {-1, -1 ,2} 这组数据,当遍历到 第一个 -1 的时候,只要前一位没有-1,那么 {-1, -1 ,2} 这组数据一样可以收录到 结果集里。

这是一个非常细节的思考过程。

代码主体:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
    // 找出a + b + c = 0
        // a = nums[i], b = nums[left], c = nums[right]
        for (int i = 0; i < nums.length; i++) {
        // 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
            if (nums[i] > 0) { 
                return result;
            }

            if (i > 0 && nums[i] == nums[i - 1]) {  // 去重a
                continue;
            }

            int left = i + 1;
            int right = nums.length - 1;
            while (right > left) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum > 0) {
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
            // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                    while (right > left && nums[right] == nums[right - 1]) right--;
                    while (right > left && nums[left] == nums[left + 1]) left++;
                    
                    right--; 
                    left++;
                }
            }
        }
        return result;
    }
}

 

标签:right,nums,int,三数,三元组,LeetCode15,left
From: https://www.cnblogs.com/zhz123567/p/17242695.html

相关文章

  • LeetCode 16. 最接近的三数之和
    classSolution{public:intthreeSumClosest(vector<int>&nums,inttarget){intn=nums.size();pair<int,int>res(INT_MAX,0);//分别存储差......
  • LeetCode 15. 三数之和
    classSolution{public:vector<vector<int>>threeSum(vector<int>&nums){vector<vector<int>>res;sort(nums.begin(),nums.end());......
  • 代码随想录训练营day9|第454题.四数相加II,383. 赎金信,第15题. 三数之和,
    第454题.四数相加II题目链接:第454题.四数相加II题目描述:给定四个包含整数的数组列表A,B,C,D,计算有多少个元组(i,j,k,l),使得A[i]+B[j]+C[k]+D[l]=......
  • 15. 三数之和
    classSolution{//定义三个指针,保证遍历数组中的每一个结果//画图,解答publicList<List<Integer>>threeSum(int[]nums){//定义一个结果集......
  • 15. 三数之和
    给你一个整数数组 nums ,判断是否存在三元组 [nums[i],nums[j],nums[k]] 满足 i!=j、i!=k 且 j!=k ,同时还满足 nums[i]+nums[j]+nums[k]==0 。请......
  • 16. 最接近的三数之和
    给定一个包括 n个整数的数组 nums 和一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一......
  • 三数之和---双指针
    三数之和给你一个整数数组nums,判断是否存在三元组[nums[i],nums[j],nums[k]]满足i!=j、i!=k且j!=k,同时还满足nums[i]+nums[j]+nums[k]==0。请你......
  • 返回三数之和为0的三元组.
    //给你一个整数数组 nums ,判断是否存在三元组 [nums[i],nums[j],nums[k]] 满足 i!=j、i!=k且 j!=k ,同时还满足 nums[i]+nums[j]+nums[k]==0 。请......
  • 代码随想录day7|454. 四数相加 II、383. 赎金信、15. 三数之和、18. 四数之和
    四数相加||1,简单的两层for循环map.put(i+j,map.getOrDefault(i+j,0));2, res+=map.getOrDefault(-i-j,0); 赎金信1,定义一个26长的数组记录res[......
  • leetcode 16. 最接近的三数之和
    先排序,解决两数之和之后从i开始,解决i以后的tar-nums[i]的两数的最近和#include<bits/stdc++.h>usingnamespacestd;#definedebug(x)cout<<#x<<":"<<x<<endl;......