2、三数之和

探讨如何在给定数组中寻找所有不重复的三元组,使其和为零。通过排序和双指针技巧优化算法,避免重复计算,提高搜索效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

对时间要求特别严格,因此时刻要注意着节约,因此使用set集合来区别是否有重复的,先进行排序这样一来可以使用双指针,并且使用一个判断来避免重复的元素,这样能提高一点性能
代码(无数次的超时才在提示下撸出来效率不高的代码)

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
Set<List<Integer>> tem1 = new HashSet<>();
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		//换一个思路,遍历数组并且设置前后指针
		
		
		//先进行排序一下
		Arrays.sort(nums);
		
		for (int i = 0; i < nums.length; i++) {
			int j = nums[i];
			int goal = -j;
			int start = i+1;
			int end = nums.length -1;
			while (start < end) {
				if(nums[start] + nums[end] > goal){
					end --;
				}else if (nums[start] + nums[end] < goal) {
					start ++;
				}else {
					List<Integer> tem = new ArrayList<>();
					tem.add(j);
					tem.add(nums[start]);
					tem.add(nums[end]);
					tem1.add(tem);
					int t = nums[start];
					while(nums[start] == t){
						start ++;
						if(start >= end){
							break;
						}
					}
					t = nums[end];
					while(nums[end] == t){
						end --;
						if(start >= end){
							break;
						}
					}
					
					
				}
				
			}
			
		}
		
		
		for (List<Integer> list : tem1) {
			result.add(list);
		}
		return result;        
    }
}

排名靠前的代码
有点复杂

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        if (nums.length < 3)
                return Collections.emptyList();
            List<List<Integer>> res = new ArrayList<>();
            int minValue = Integer.MAX_VALUE;
            int maxValue = Integer.MIN_VALUE;
            int negSize = 0;
            int posSize = 0;
            int zeroSize = 0;
            for (int v : nums) {
                if (v < minValue)
                    minValue = v;
                if (v > maxValue)
                    maxValue = v;
                if (v > 0)
                    posSize++;
                else if (v < 0)
                    negSize++;
                else
                    zeroSize++;
            }
            if (zeroSize >= 3)
                res.add(Arrays.asList(0, 0, 0));
            if (negSize == 0 || posSize == 0)
                return res;
            if (minValue * 2 + maxValue > 0)
                maxValue = -minValue * 2;
            else if (maxValue * 2 + minValue < 0)
                minValue = -maxValue * 2;

            int[] map = new int[maxValue - minValue + 1];
            int[] negs = new int[negSize];
            int[] poses = new int[posSize];
            negSize = 0;
            posSize = 0;
            for (int v : nums) {
                if (v >= minValue && v <= maxValue) {
                    if (map[v - minValue]++ == 0) {
                        if (v > 0)
                            poses[posSize++] = v;
                        else if (v < 0)
                            negs[negSize++] = v;
                    }
                }
            }
            Arrays.sort(poses, 0, posSize);
            Arrays.sort(negs, 0, negSize);
            int basej = 0;
            for (int i = negSize - 1; i >= 0; i--) {
                int nv = negs[i];
                int minp = (-nv) >>> 1;
                while (basej < posSize && poses[basej] < minp)
                    basej++;
                for (int j = basej; j < posSize; j++) {
                    int pv = poses[j];
                    int cv = 0 - nv - pv;
                    if (cv >= nv && cv <= pv) {
                        if (cv == nv) {
                            if (map[nv - minValue] > 1)
                                res.add(Arrays.asList(nv, nv, pv));
                        } else if (cv == pv) {
                            if (map[pv - minValue] > 1)
                                res.add(Arrays.asList(nv, pv, pv));
                        } else {
                            if (map[cv - minValue] > 0)
                                res.add(Arrays.asList(nv, cv, pv));
                        }
                    } else if (cv < nv)
                        break;
                }
            }
            return res;
        
    }
}

相对靠前的代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list=new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        for (int i = 0; i <nums.length-1 ; i++) {
            if (i>0&&nums[i]==nums[i-1]){
                continue;//第一层遍历看是否和下一个值相等,相等就跳出这层循环,因为相等就会算重复,
                // 例如-1,-1,2不判断-1和-1是否相等就会第二个-1有算出一个重的
            }
            int left=i+1;//两数相加的和从i+1开始。
            int right=nums.length-1;
            while (left<right){
                if (nums[left]+nums[right]+nums[i]>0){
                    right--;
                } else if (nums[left] + nums[right] + nums[i] < 0) {
                    left++;
                }else {
                    list.add(Arrays.asList(nums[left],nums[right],nums[i]));
                    left++;right--;//就是不大于不小于0(等于0)的时候,做指针向右,右指针向左一动。

                    //这两层while就是判断如果求两数相和的时候如果左右相等就指针移动,因为走到这的时候肯定是新的
                    //left和right,所以就要左右指针一起判断和挨着的(下一个值)是不是相等,相等就用下一个值判断。
                    while (left<right&&nums[left]==nums[left-1]){
                        left++;
                    }
                    while (left<right&&nums[right]==nums[right+1]){
                        right--;
                    }
                }

            }
        }
        return list;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值