[Leetcode]3Sum

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.

    For example, given array S = {-1 0 1 2 -1 -4},

    A solution set is:
    (-1, 0, 1)
    (-1, -1, 2)

与上一题2Sum类似,但也有不同。

在2Sum中,对输出没有排序要求,也假设只有一个solution,因此,仅用一次遍历,找到可能值即返回就可以。

在3Sum中,需要排序,并且返回所有可能值同时不能有重复,因此简单的遍历不成功了。但其实3Sum分解出来就是先找一个数,让其相反数作为2Sum的target,然后运行一遍2Sum。在上一篇博客中的2Sum算法仅针对2Sum题目要求,不具备返回所有可能结果以及去重的功能。因此需要一个更好的2Sum算法。最直观的思路就是先选一个数,令其相反数作为target,然后在剩余的数当中选两个,让他们相加等于这个数。但如果输入是无序的,这个过程需要耗费O(n3)的时间,很显然太naive了。

一个相对好的方法是对输入数组排序,然后从最小数开始,选出一个的相反数作为target,然后在剩下的数中用两个指针,分别指向剩余数组的首尾。首指针start递增,尾指针end递减。如果首尾相加刚好等于target,说明找到一个符合条件的解。如果首尾相加小于target,意味着两个加数太小,需要递增start指针。如果首尾相加大于target,意味着两个加数太大,需要递减end指针。当然在指针递增和递减的过程中,要考虑略过已经测试过的重复值。这样一来,算法复杂度减小为O(n2)。因此最初的排序算法用O(nlogn)也不会对复杂度产生影响。具体代码如下:


public List<List<Integer>> threeSum(int[] num) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if (num == null || num.length < 3) {
            return res;
        }
        
        Arrays.sort(num);
        for (int i = 0; i < num.length - 2; i++) {
            if (i == 0 || num[i] > num[i - 1]) {
                int negate = -num[i];
                int start = i + 1;
                int end = num.length - 1;
                while (start < end) {
                    if (num[start] + num[end] == negate) {
                        List<Integer> item = new ArrayList<Integer>();
                        item.add(num[i]);
                        item.add(num[start]);
                        item.add(num[end]);
                        
                        res.add(item);
                        start++;
                        end--;
                        
                        while (start < end && num[start] == num[start - 1]) {
                            start++;
                        }
                        
                        while (start < end && num[end] == num[end + 1]) {
                            end--;
                        }
                    } else if (num[start] + num[end] < negate) {
                        start++;
                    } else {
                        end--;
                    }
                }
            }
        }
        return res;
    }


3Sum closest

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

这是一个和3Sum相似的问题,也可以用相同的思路解决。不同之处在于需要维护一个最小偏差。

public int threeSumClosest(int[] num, int target) {
        if (num == null || num.length < 3) {
            return 0;
        }
        Arrays.sort(num);
        
        int minDif = Integer.MAX_VALUE;
        int closest = 0;
        for (int i = 0; i < num.length - 2; i++) {
            int start = i + 1;
            int end = num.length - 1;
            while (start < end) {
                int tmp = num[i] + num[start] + num[end];
                int dif = tmp - target;
                if (Math.abs(dif) < minDif) {
                    minDif = Math.abs(dif);
                    closest = tmp;
                }
                
                if (tmp < target) {
                    start++;
                } else {
                    end--;
                }
            }
        }
        return closest;
    }




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值