1st round, 15 3Sum

2sum, 3sum 是典型的考查排序后数组的特性的一道题,一旦将数组排序,加和的话就通过 夹逼法 实现就可以。。。

如果数组内有重复数据出现,那么要考虑,是否可以过滤掉一些重复元素,在夹逼过程中,可以滑过一整段相同的数字,而不是每跳到一个数字就计算考察一下。。


public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list = new  ArrayList<>(); // !!! my knowledge for container is so short
        if(nums==null || nums.length<3) return list;
        
        Arrays.sort(nums);
        for(int i=0; i<nums.length-2; i++){
            while((i>0) && nums[i]==nums[i-1]&& i<nums.length-3) i++;
            if(nums.length>3 && i==(nums.length-3) && nums[nums.length-4]==nums[nums.length-3] ) return list;
            // NB!!!!!! And the conditions in if() while() matters in ORDER!! safe to put the length first
            // this is a FRAGMENT code, added because of an error
            //while((i>0) && nums[i]==nums[i-1]&& i<nums.length-3) i++; // i<nums.length-3!! not i<nums.length-2!!
            // since I hecked the previous i in last loop, so in order to avoid duplication, I should skip the same nums[] here
            
            //while(nums[i]==nums[i+1]) i++; // get the last element of a sequence of same element, but this is wrong, since the starting point cannot be ignored, they can be a element!!! the only time you can ignore is when you find the match.
            
            int l=i+1;
            int r=nums.length-1;
            while(l<r){
                //while(nums[l]==nums[l+1] && (l+1)<r) l++;
                //while(nums[r-1]==nums[r] && l<(r-1)) r--;
                
                int sum=nums[l]+nums[r];
                if(sum==-nums[i]){
                    List<Integer> item = new ArrayList<>();
                    item.add(nums[i]);
                    item.add(nums[l]);
                    item.add(nums[r]);
                    list.add(item);
                    while(nums[l]==nums[l+1] && (l+1)<r) l++; // 1: update either l or r is okay, updating both could be a little faster. 2: (l+1)<r !!! since you are in a while loop, you can constantly comparing: nums[l]==nums[l+1]. !!! So keep index with legal bounds
                    l++;    // after while loop, l is at the position of last element of sequence of same elem, so have to ++ 
                    //while(nums[l]==nums[l+1] ) l++;
                    //while(nums[r-1]==nums[r] ) r--;
                    // or r--; does not matter, but have to updata either l or r
                }
                else if(sum<-nums[i]) l++;
                else if(sum>-nums[i]) r--;
                
            }
        }
        return list;
    }
}

我今天写了第二遍,思路比上面的要清晰流畅一些。。。但是要注意的重点是:无论是i还是left,right,都需要先进位,然后再通过while()来判断是否跨过重复元素。。。我在ppt中有所标记,代码如下:


        List<List<Integer>> list= new ArrayList<>();
        int len= nums.length;
        if(len<3) return list;
        
        Arrays.sort(nums);
        for(int i=0; i<len-2; i++){
            while(i>0 && i<len-2 && nums[i]==nums[i-1]) i++; // 这里和下面的left,right的处理一模一样,只是说i在每次进for loop都+1了,所以不需要写,想想for就是while的一种简略写法,只不是把i++综合在一起写进来了。。。所以这里只需要直接通过while来判断。。。弄清楚这个了之后的固定i的三种变化情况,==, >, < 都是做同样处理。。。
            int left=i+1;
            int right=len-1;
            while(left<right){
                int sum=nums[i]+nums[left]+nums[right];
                if(sum==0){
                    list.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[left],nums[right])));
/*                    List<Integer> match= new ArrayList<>();
                    match.add(nums[i]);
                    match.add(nums[left]);
                    match.add(nums[right]);
                    list.add(match);*/
                    //break;  // 这是不能break的,在找到一个match之后,还会有其他match比如,  [1,2,...,8,9] 1+9 和 2+8 都是match
                    left++;
                    while(left<right && nums[left]==nums[left-1]) left++;
                    right--;
                    while(left<right && nums[right]==nums[right+1]) right--;
                    //while(right>left && nums[right-1]==nums[right]) right--;
                }
                else if(sum<0){
                    //while(left<right && nums[left+1]==nums[left]) 
                    left++;
                    while(left<right && nums[left]==nums[left-1]) left++;
                }
                else{
                    //while(right>i && nums[right-1]==nums[right]) 
                    right--;
                    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、付费专栏及课程。

余额充值