15. 3Sum

Posted limaodeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15. 3Sum相关的知识,希望对你有一定的参考价值。

1.题目描述

英文版:

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0?

Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]]

中文版:

给一个长度为n的数组nums。在数组nums里面有三个数a,b,c。并且a + b + c = 0。

在数组中找出所有唯一的三元组,其总和为零。

注意:

在结果集里面必须不能包含重复的三元组。

例如:

数组 nums = [-1, 0, 1, 2, -1, -4],

它的结果集:
[
[-1, 0, 1],
[-1, -1, 2]]

2.解法

2.1 解法1

思路:

看到这一题,最先的想法也是暴力破解法。三重循环分别遍历所有数的三元组之和,遍历之前先进行排序,后面用来比较是否为重复三元组。但是这种写法很明显,时间复杂度实在是太高了,在LeetCode上运行没有通过。

    public static List<List<Integer>> threeSum1(int[] nums) {
        Arrays.sort(nums);  //先进行排序,后面方便查重
        List<List<Integer>> lists = new ArrayList<>();
        for(int i = 0;i < nums.length;i++){
            for(int j = i + 1;j < nums.length;j++){
                for(int k = j + 1;k < nums.length;k++){
                    if(nums[i] + nums[j] + nums[k] == 0){
                        List<Integer> list = new ArrayList<>();
                        list.add(nums[i]);
                        list.add(nums[j]);
                        list.add(nums[k]);
                        //判断lists里面是否包含有元素一模一样的list,如果有则不添加,如果没有则添加
                        AtomicBoolean b = new AtomicBoolean(false);
                        lists.forEach(li -> {
                            if(li.get(0)==list.get(0)&&
                                    li.get(1)==list.get(1)&&
                                    li.get(2)==list.get(2)){
                                b.set(true);
                            }
                        });
                        if(!b.get()){
                            lists.add(list);
                        }
                    }
                }
            }
        }
        return lists;
    }

在LeetCode上运行的结果:

技术图片

2.2 解法2

思路:

这种解法较好地优化了时间复杂度。首先在遍历之前也选对数组进行排序,方便后面操作。排好迅之和,从左边到右边,先找到i位置对应的数,再找出start位置和end位置的数,使他们相加起来等于i位置的数的相反数,这就是一组数。其中start的位置从i+1开始往后移,end的位置从nums.length - 1开始往前移。

注意的点:

1、只循环到倒数第三个数即可
2、如果nums[i]大于零,说明后面没有数跟它相加起来等于零了
3、空数组则直接返回
4、如果第i个的前一个与它相等,则跳过,避免重复三元组
5、第start+1的数与第start相等则跳过,继续往后找,避免重复三元组
6、第end - 1的数与第end相等则跳过,继续往前找,避免重复三元组
7、如果nums[start] + nums[end] < target ,则说明start所处的位置还太小,start继续往后找
8、如果nums[start] + nums[end] > target,则说明end所处的位置还太大, 则end继续往前找

代码实现:
    public static List<List<Integer>> threeSum2(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();
        Arrays.sort(nums);  //先对数组进行排序
        for(int i = 0;i < nums.length - 2;i++){  //只循环到倒数第三个数即可
            if(nums[i] > 0) break;  //如果nums[i]大于零,说明后面没有数跟它相加起来等于零了
            if(nums.length == 0) break; //空数组则直接返回
            if(i > 0 && nums[i] == nums[i-1]) continue; //如果第i个的前一个与它相等,则跳过,避免重复数据
            int target = 0 - nums[i];   //将第i个数变成正数
            int start = i + 1;  //start从第i+1开始往后移
            int end = nums.length - 1; //end从第nums.length - 1开始往前移
            while (start < end){
                if(nums[start] + nums[end] == target){ //num[i] + nums[start] + nums[end] = 0
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[start]);
                    list.add(nums[end]);
                    lists.add(list);
                    while (start < end && nums[start] == nums[start + 1]) //第start+1的数与第start相等则跳过,继续往后找
                        start++;
                    while (start < end && nums[end] == nums[end - 1]) //第end - 1的数与第end相等则跳过,继续往前找
                        end--;

                    start++;
                    end--;
                }else if(nums[start] + nums[end] < target){ //nums[start] + nums[end] < target 则start继续往后找
                    start++;
                }else { //nums[start] + nums[end] > target 则end继续往前找
                    end--;
                }
            }
        }
        return lists;
    }    

在LeetCode上运行的结果:

技术图片

3.测试

在本地,我只是简单写了一个main函数来对它进行测试。但是这些代码都是在LeetCode上运行通过了的。

    public static void main(String[] args) {
        int[] nums = {-1, 0, 1, 2, -1, -4};
        List<List<Integer>> lists = threeSum2(nums);
        lists.forEach(s -> {
            s.forEach(k -> System.out.print(k + " "));
            System.out.println();
        });
    }
欢迎关注个人公众号,可直接扫描以下二维码或微信搜索“阿毛聊技术”。

技术图片

以上是关于15. 3Sum的主要内容,如果未能解决你的问题,请参考以下文章

15. 3Sum

15. 3Sum

15. 3Sum

leetcode 15 3Sum

[leetcode][15] 3Sum

15. 3Sum