zoukankan      html  css  js  c++  java
  • 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;
        }
        
    }



  • 相关阅读:
    20201216-1 文件读与写详解3
    20201214-4 文件读与写详解2
    20201214-3 文件读与写详解1
    20201214 集合及其运算
    3月17日:毕业设计计划
    3月16日:毕业设计计划
    3月15日:毕业设计计划
    3月14日:毕业设计计划
    3月13日:毕业设计计划
    3月12日:毕业设计计划
  • 原文地址:https://www.cnblogs.com/dosmile/p/6444433.html
Copyright © 2011-2022 走看看