LeetCode | 3 Sum

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)

方法一:

//基本的brute force方法:在eclipse上运行是可以的,也满足三元组中的非降序
//及无重复三元组的要求。但是提示超时,不accept。算法复杂度为O(n^3)
public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(nums.length < 3) return result;
        
        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){
                        Integer[] array = {nums[i], nums[j], nums[k]};
                        Arrays.sort(array);                //对三元组排序
                        List<Integer> list = new ArrayList<Integer>();
                        list.addAll(Arrays.asList(array)); //addAll方法参数只能为collection
                        if(!result.contains(list)){        //能够达到去除重复三元组的效果
                            result.add(list);
                        }
                    }
                    
                }
            }
        }
        
        return result;
    }
}


方法二:

/引入二分查找,要求返回数组元素值而非index,故可先排序,再找元素
//理论上,算法复杂度为O(n^2*logn),在eclipse上执行也可以(没细对比,可能有误)
//提示超时,不accept
public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(nums.length < 3) return result;
        
        Arrays.sort(nums);
        for(int i=0; i<nums.length; i++){
            for(int j=i+1; j<nums.length; j++){
                
                int head = j + 1;
                int tail = nums.length - 1;
                int needNum = -(nums[i]+nums[j]);
                
                while(head <= tail){              //二分查找
                    int middle = (head+tail) / 2;
                    if(nums[middle] == needNum){
                        List<Integer> list = new ArrayList<Integer>();
                        list.add(nums[i]);
                        list.add(nums[j]);        //已经排序过了,无需再排序了
                        list.add(nums[middle]);
                        if(!result.contains(list)){
                            result.add(list);
                        }
                        break;           //二分查找到结果之后,一定要break,否则head=tail时会无限循环
                    }else if(nums[middle] > needNum){
                        tail = middle - 1;
                    }else if(nums[middle] < needNum){
                        head = middle + 1;
                    }
                }
                
            }
        }
        
        return result;
    }
}


方法三:(accept)

//排序花费O(nlogn),遍历花费O(n^2),总复杂度为O(n^2)
public class Solution {
    //主调方法
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(nums.length < 3) return result;
        
        Arrays.sort(nums);
        for(int i=nums.length-1; i>=2; i--){   //每次取nums[i],然后在nums[0~i-1]中寻找两和为-nums[i]的
            
            if(i<nums.length-1 && nums[i]==nums[i+1]){    //遇到重复的nums[i]就跳过
                continue;
            }
                                                          //方法调用,找sum为-nums[i]的pair
            List<List<Integer>> tempCollection = twoSum(nums, i-1, -nums[i]);
            
            for(int j=0; j<tempCollection.size(); j++){
                List<Integer> tempList = tempCollection.get(j);
                tempList.add(nums[i]);                    //把二元组扩充为三元组
                result.add(tempList);
            }
        }
        
        return result;
    }
    
    //被threeSum调用的辅助方法,思想类似于昨天twoSum中的夹逼思想,但是要注意跳过重复的元素
    //下面的方法中,参数nums是应经排序过的数组,故调用此方法只需要O(n)的复杂度
    private List<List<Integer>> twoSum(int[] nums, int end, int target) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(nums.length < 2) return null;
        int left = 0;
        int right = end;
        while(left < right){                                     //夹逼的思想
            if(nums[left]+nums[right] == target){
                List<Integer> list = new ArrayList<Integer>();
                list.add(nums[left]);
                list.add(nums[right]);
                result.add(list);
                
                left++;
                right--;
                while(left<right && nums[left]==nums[left-1]){   //跳过重复的元素
                    left++;
                }
                while(left<right && nums[right]==nums[right+1]){ //跳过重复的元素
                    right--;
                }
            }else if(nums[left]+nums[right] > target){
                right--;
            }else if(nums[left]+nums[right] < target){
                left++;
            }
        }
        return result;
    }
    
}



原文地址:https://www.cnblogs.com/dosmile/p/6444433.html