LeetCode 15. 3Sum

题目:

给定一个包含n个整数的数组,在数组中是否存在a、b、c元素使得a + b + c = 0?找出数组中所有唯一的三胞胎,它们的和为零

注意:不能包含重复的三元组。

Given an array nums of n integers, are there elements abc 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.

Given array nums = [-1, 0, 1, 2, -1, -4],  A solution set is:[ [-1, 0, 1], [-1, -1, 2] ]

参考:

https://www.cnblogs.com/wangkundentisy/p/9079622.html

方法:

方法1:

先得到所有三个数不重复的组合,再每个组合求是否和为0,不为0则删除

果然超时了。。。在写出三个for的时候我眉头一皱发现事(肯)情(定)有(超)点(时)不(了)对 TAT

 

方法2:

先对数组进行排序

从第一个数nums[i]开始,寻找相加等于-nums[i](或者说与nums[i]相加等于0的两个数),寻找的方法为:

分别放两个指针,leftLoc=i+1,rightLoc=nums.length-1

循环条件:leftLoc<rightLoc

步骤:

1. 三数相加,如果等于0:将数组加入到结果re中,并将两个指针都往中间走

2. 如果结果小于0,则表示结果偏小,将leftLoc往中间走

3. 如果结果大于0,则表示结果偏大,将rightLoc往中间走

【注意】由于要求不能有重复,所以在遍历数组中的每个数,以及,将两个指针往中间挪动的时候,需要注意,如果所处的数不是边界值,则比较其当前值与上一个值是否相同,如果相同,则直接跳过——在挪动过程中也需要判断leftLoc<rightLoc,以防越界

(举的例子中没有相加可以为0的,只是举例说明位置挪动的方式)如1 1 2 2 3 4 5 6 6 6,在整体遍历时,如果对第一个1进行了查找,则第二个1直接跳过;在进行指针挪动时,如果左指针在第一个2的位置,则下一个左指针的位置应该为3,;如果右指针在最右的6的位置,则下一个右指针的位置应该为5的位置

 

代码:
 

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> re = new LinkedList<List<Integer>>();
        Arrays.sort(nums);
        for(int i=0;i<nums.length-2;i++) {    	
            // 跳过重复值
            if(i!=0 && nums[i]==nums[i-1]) {
                continue;
            } 
    		
            // 左右指针位置
    		int leftLoc = i+1;
    		int rightLoc = nums.length-1;
   
            // 进入循环
            while(leftLoc<rightLoc) {
                int temp = nums[i]+nums[leftLoc]+nums[rightLoc];
                // 如果相加为0
                if(temp==0) {
                    List<Integer> t = new LinkedList<Integer>();
                    t.add(nums[i]);
                    t.add(nums[leftLoc]);
                    t.add(nums[rightLoc]);
                    re.add(t);
                    
                    // 左右指针在进行跳过重复时 都要先自己挪动一步
                    // 因为在当前位置 不符合nums[leftLoc]==nums[leftLoc-1]
                    // 当然也阔以自己改成其他的条件~
                    // 下面两种情况中同理
                    leftLoc++;
                    while(leftLoc<rightLoc && nums[leftLoc]==nums[leftLoc-1]) {
                        leftLoc++;
                    }
                    rightLoc--;
                    while(leftLoc<rightLoc && nums[rightLoc]==nums[rightLoc+1]) {
                        rightLoc--;
                    }
                }else {
                    // 相加小于0 挪左指针
                    if(temp<0) {
                        leftLoc++;
                        while(leftLoc<rightLoc && nums[leftLoc]==nums[leftLoc-1]) {
                            leftLoc++;
                        }
                    }else 
                    // 相加大于0 挪右指针
                    if(nums[i]+nums[leftLoc]+nums[rightLoc]>0){
                        rightLoc--;
                        while(rightLoc>leftLoc && nums[rightLoc]==nums[rightLoc+1]) {
                            rightLoc--;
                        }
                    }
                }
            }
        }
        return re;
    }
}

 

// 超时的三个for循环 嘿嘿嘿
public static List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> re = new LinkedList<List<Integer>>();
    Arrays.sort(nums);
    for(int i=0;i<nums.length-2;i++) {
        if(((i>0 && nums[i]!=nums[i-1]) || i==0) && nums[i]<=0) {
            for(int j=i+1;j<nums.length-1;j++) {
                if(nums[j]!=nums[j-1] || j==i+1) {
                    for(int k=j+1;k<nums.length;k++) {
                        if(nums[k]!=nums[k-1] || k==j+1) {
                            if(nums[k]+nums[j]+nums[i]==0) {
                                List<Integer> temp = new LinkedList<Integer>();
                                temp.add(nums[i]);
                                temp.add(nums[j]);
                                temp.add(nums[k]);
                                re.add(temp);
                            }
                        }
                    }
                }
            }
        }
    }
    return re;    
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值