每天一到算法题——三数之和

题目
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。
示例

给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum

暴力求解超时了。。。。。三重循环,加去掉重复的三元组直接给干超时了。
没做出来。
参考官方的思路:
由a+b+c=0可知,我们需要遍历数组得到a,b,c。怎么遍历?使用三重for循环。假设for循环中所在的索引位置为i, j, k,使用三重for循环首先得排除一个情况,就是i, j, k不在同一个位置,为什么? 如果输入数组是[0,2,1],假设i, j, k刚开始在同一个位置开始一次遍历,那么得到的第一个序列就很明显不满足题目要求。那么在这里什么叫做不重复?怎么样保证不重复?

  1. 保证第一层循环的值小于第二层
  2. 保证第二层循环的值小于第三层

这样,就可以保证不重复。怎么做到呢?只需要对数组进行从小到大排序。就只有(a, b, c)而不会出现(b, c, a), (c, b, a)这种情况。
排序以后,可能有重复的元素,那么重复的元素可能会不满足要求。比如下图显然是满足要求:
在这里插入图片描述
因为此时i, j, k还在初始位置。但是下图就不满足要求了:
在这里插入图片描述
这种情况是k向右移动了一个位置,这个时候需要跳过这种情况。
我们发现,假设a+b+c=0,下一次遍历如果得到a+b’+c’=0,此时,b’>b,那么要满足a+b’+c’=0必须使得c’<=c,也就是说c’一定是在c的左边,且要在b的右边,也就是说可以并列执行第二层循环(从左到右得到b)和第三层循环(从右到左得到c)。那么可以在从右到左遍历数组得到c,停止遍历的条件是c对应的索引位置不大于b对应的索引位置,或者a+b+c的和不大于0。

算法

public List<List<Integer>> threeSum(int[] nums) {
    
    
        List<List<Integer>>ans=new ArrayList();
       Arrays.sort(nums);
       int length=nums.length;
        for(int i=0;i<length;++i){
    
    
            if(i>0&&nums[i]==nums[i-1]) continue;
            int target=-nums[i];
            for(int j=i+1;j<length;++j){
    
    
                if(j-1>i&&nums[j]==nums[j-1]) continue;
                int k=length-1;
                while(k>j&&nums[j]+nums[k]>target) --k; 
                if(k==j) break;
                if(nums[k]+nums[j]==target){
    
    
                    List<Integer>list=new ArrayList(3);
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[k]);
                    ans.add(list);
                }
            } 
        }
        return ans;
    }

猜你喜欢

转载自blog.csdn.net/weixin_43763175/article/details/109553266