牛客刷题——数组中和为0的三元组

题目:给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。

注意:

  1. 三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
  2. 解集中不能包含重复的三元组。

这道题,我是想着直接用暴力求解,三重循环。。。结果答案对比是一样的,这个测试就是不给我通过,就很奇怪,然后就去看了其他人的题解,使用的是双指针,整体思想是把三数和为0转换为两数和为0 ,还是有几个需要注意的点的。

首先为了方便处理,先将数组进行排序,(以后类似的题目都要注意,对顺序没有要求的,并且是乱序的,先去考虑一下对数组排序是不是能够简化处理),将数组排序之后就使得我们找三个和为0的数字有规律可循,并且能够简化很大部分的比较。

首先使用循环对第 0 - num.length-3的元素进行遍历,通过确定当前元素,将三数之和转换为了两数之和,在每次进行处理之前需要进行一步去重操作,由于解集是要求不包含重复三元组的,因此如果当前元素等于其前一个元素的话就直接跳过不用处理,对于每个需要处理的元素 i ,首先确定 left = i+1,right = num.length-1,然后对num[i] , num[left] , num[right] 三数之和进行判断,

1)当 left<right 并且三数之和大于0时,说明 right 需要左移,因为数组是升序排序的,右移变大,左移变小,所以需要 right 左移来减小三数之和。

2)当 left<rigjt 并且三数之和等于0时,好的,找到一组解了,将三个数 add 进 list 中,然后 sort 一下,然后添加到最终结果的 list 中。做完这一步需要注意,由于left和right的遍历还在继续,为了避免重复的三元组,我们需要将 left 右边的等于 left 的元素跳过,left++进行右移。

3)left<right 并且三数之和小于0的话,那么 left 右移移来增大三数之和。

完整代码如下:

public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        Arrays.sort(num);
    	for(int i=0;i<=num.length-3;i++) {
    		if(i==0||num[i]!=num[i-1]) {//跳过重复数字
    			int left = i+1;
    			int right = num.length-1;
    			while(left<right) {
    				while (left<right&&((num[i]+num[left]+num[right])>0)) { //大于0的话让right变小
    					right--;						
					}
    				if(left<right&&num[i]+num[left]+num[right]==0) {
    					ArrayList<Integer> temp = new ArrayList<Integer>();
        				temp.add(num[i]);
        				temp.add(num[left]);
        				temp.add(num[right]);
        				Collections.sort(temp);
        			    res.add(temp);
                        int templeft = num[left];
        				while(left<right&&num[left]==templeft) {
        					left++;
        				}
    				}else {
						left++;
					}
    			}
    		}
    	}
    	return res;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值