leetcode#15

每日leetcode

Posted by Cfeng on May 7, 2019

三数之和

题目描述

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

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

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

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

思路

三数之和,暴力循环 O(N^3)肯定TLE所以不考虑
那么可以把时间复杂度暂定于O(N^2)
所以我们可以先排个序,然后再考虑; 因为遍历数组不可能避免,所以最外一层循环就是遍历。接着我们要考虑剩下一重循环怎么写。
因为最小数已经确定,我们只要使剩下两数之和为最小数的相反数即可,所以可以定义两个指针分别表述最小数后一个数,与最大数,然后两指针向中间靠拢,用一重循环,确定两数。 靠拢的条件就是三数之和小于0,那么小的要变大,t如果三数之和大于0,那么大的要变小。
大致逻辑框架就是这样。接下来要保证不会重复。 1.两指针判断一个数是否相等,若是则直接移动。 2.同一个数作为最小数一次即可,两次必然会重复

之后要考虑是否有特殊情况,例如传进来的数组长度是否小于3,或者是否传递空值等。
这两种情况不能返回null(被坑了一次。。。)。
最 后就是考虑能否优化,比如说最小数大于0,那么一定不存在解了,可以直接返回。

Java实现

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if(nums==null||nums.length<3){
            return res;
        }
        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 j=i+1;
                int k=nums.length-1;
                while(j<k){
                    if(nums[i]+nums[j]+nums[k]==0){
                        res.add(Arrays.asList(nums[i], nums[j], nums[k]));
                        while(j<k){
                            if(nums[j]==nums[j+1]) j++;
                            else if(nums[k]==nums[k-1]) k--;
                            else break;
                        }
                        j++;
                        k--;
                    }
                    else if(nums[i]+nums[j]+nums[k]<0){
                        j++;
                    }
                    else k--;
            }
        }
        return res;
    }
}

执行用时 : 54 ms, 在3Sum的Java提交中击败了95.66% 的用户
内存消耗 : 53.1 MB, 在3Sum的Java提交中击败了80.37% 的用户