leetcode-15-三数之和


title: leetcode-15-三数之和
date: 2019-09-03 08:24:55
categories:

  • leetcode
    tags:
  • leetcode

三数之和

  • 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

    注意:答案中不可以包含重复的三元组。

    例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

    满足要求的三元组集合为:
    [
    [-1, 0, 1],
    [-1, -1, 2]
    ]

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/3sum
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 解法一:唯有暴力深得我心

        public static List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> list= new ArrayList<>();
            Arrays.sort(nums);
            for (int i=0;i<nums.length-2;i++){
                for (int j=i+1;j<nums.length-1;j++)
                    for (int k=j+1;k<nums.length;k++){
                        if (nums[i]+nums[j]+nums[k]==0){
                           if (!list.contains(Arrays.asList(nums[i],nums[j],nums[k])))
                                list.add(Arrays.asList(nums[i],nums[j],nums[k]));
                        }
                    }
            }
            return list;
        }
    

    结果:超出时间限制

  • 解法二:双指针法

    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> list= new ArrayList<>();
            if (nums.length<3)
                return list;
            Arrays.sort(nums);
            for (int i=0;i<nums.length-2;i++){
                if(nums[i]>0)
                    break;
                if(i>0&&nums[i]==nums[i-1])
                    continue;
                int left = i+1;
                int right = nums.length-1;
                while (left<right){
                    int a = nums[i]+nums[left]+nums[right];
                    if(a==0){
                        list.add(Arrays.asList(nums[i],nums[left],nums[right]));
                        while(left<right&&nums[left]==nums[left+1])
                            left = left+1;
                        while(left<right&&nums[right]==nums[right-1])
                            right = right-1;
                        left++;
                        right--;
                    }else if (a<0){
                        left++;
                    }else {
                        right--;
                    }
                }
            }
            return list;
        }
    }
    

    解释:

    1. 首先用java内置的方法进行排序,判断如果nums的数组长度小于3,那么就没有三个数也就不可能相加,直接返回空的list即可
    2. 选择前面n-2个数当作c位,如果c位都>0那么直接跳出就可以(sort排序默认从小到大),如果这个c位和上一个c位相等,那么直接continue就好,为什么?因为上一个c位已经做了这个c位该做的事情
    3. 进入双指针循环模式,看得出,如果小于0,left++;如果大于0;right–
    4. while条件判断,我觉的大家都会
      leetcode-15-三数之和_第1张图片
  • 高深莫测的解法:我没看懂,但是排名第一,大家可以一起讨论一下

    class Solution {
        
        public List<List<Integer>> threeSum(int[] nums) {
    		int len = nums.length;
    		if (len < 3)
    			return new ArrayList<List<Integer>>();
            
            Arrays.sort(nums);  //sort the array first
            List<List<Integer>> res = new ArrayList<>();
            int max = Math.max(nums[len - 1], Math.abs(nums[0])); //to allocate enough space to avoid check in if statement
                                 
    		byte[] hash = new byte[(max<<1) + 1];
    		for (int v : nums) { //hash and count appearing times of every num
    			hash[v + max]++;
    		}
            
            int lastNeg = Arrays.binarySearch(nums, 0); //search the position of 0; it also means the position of the last negative number in array
            int firstPos = lastNeg; //the position of the first positive number in array
            if(lastNeg < 0){    //0 not found
                firstPos = ~lastNeg;
                lastNeg = -lastNeg - 2;//see the Java api
            }
            else{               //found
                while(lastNeg >=0 && nums[lastNeg] == 0) //skip all 0
                    --lastNeg;
                while(firstPos < len && nums[firstPos] == 0)
                    ++firstPos;
                int zeroCount = firstPos - lastNeg - 1;
                if (zeroCount >= 3) { // (0 appears 3 times at least)
                    res.add(Arrays.asList(0, 0, 0));
    		    }
                if (zeroCount > 0 ) { // (0 appears 1 times at least)
    			for (int i = firstPos; i < len; ++i) { //traverse all the positive numbers to see whether there is a negative number whose absolute value equals to the positive number 
                    if(i > firstPos && nums[i] == nums[i - 1]) //skip the same elements
                        continue;
                    if ( hash[-nums[i] + max] > 0) {
    					res.add(Arrays.asList(0, nums[i], -nums[i]));
                    } 
    			}
    		}
            }
     
    		// one positive number and two negetive numbers 
    		for (int i = firstPos; i < len; ++i) { //traverse all the positive numbers to find whether there are two negative numbers to make the 3 numbers added up to 0
                if(i > firstPos && nums[i] == nums[i - 1]) //skip the same elements
                        continue;
                int half;   //we can traverse only half of the positive numbers
                if(nums[i] % 2 != 0)
                    half = -((nums[i]>>1) + 1);
                else{
                    half = -(nums[i]>>1);
                    if(hash[half + max] > 1)
                        res.add(Arrays.asList(nums[i], half, half));
                }
                for(int j = lastNeg; j >=0 && nums[j] > half; --j){
                    if(j < lastNeg && nums[j] == nums[j + 1])
                        continue;
                    if(hash[(-nums[i] - nums[j]) + max] > 0)
                        res.add(Arrays.asList(nums[i], nums[j], -nums[i] - nums[j]));
                }
            }
            
            // one negative number and two positive numbers 
    		for (int i = lastNeg; i >= 0; --i) { //traverse all the negative numbers to find whether there are two positive numbers to make the 3 numbers added up to 0
                if(i < lastNeg && nums[i] == nums[i + 1])//skip the same elements
                        continue;
                int half; //we can traverse only half of the negative numbers
                if(nums[i] % 2 != 0)
                    half = -(nums[i] / 2 - 1);
                else{
                    half = -(nums[i]>>1);
                    if(hash[half + max] > 1)
                        res.add(Arrays.asList(nums[i], half, half));
                }
                for(int j = firstPos; j < len && nums[j] < half; ++j){
                    if(j > firstPos && nums[j] == nums[j - 1])
                        continue;
                    if(hash[(-nums[i] - nums[j]) + max] > 0)
                        res.add(Arrays.asList(nums[i], nums[j], -nums[i] - nums[j]));
                }
            }
    		return res;
    	}
    }
    

    leetcode-15-三数之和_第2张图片

你可能感兴趣的:(学生,java,数据结构)