LeetCode No15. 三数之和

题目

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

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

思路

首先第一反应就是暴力,三重循环,然后时间复杂度O(n^3),按照题目给的数据范围应该不会超时,然而写完之后提交直接超时。那就优化呗,看题目的样例,似乎是对返回的顺序什么的没有要求,那么就想到排序,然后对排序后的数组去取值,这样就想到如下两种方法:

二分查找

既然三重循环不行,那我减少一层循环试试,先用两层循环找到两个数a、b,因为需要三个数之和为0,那么另外一个数必然是 -(a+b),因为数组已经有序,找这个数就可以用二分,时间复杂度为O(n^2*log(n))。

双指针

既然已经能减少一层循环,那么是否还能再减少一层循环呢?显然是可以的,用一层循环遍历出第一个数a,对于剩下的两个数,由于数组已经排好序了,只需要用两个指针去从数组的头和尾取数,只要找到的两个数和a相加等0即可。

AC代码

二分查找

点击查看代码
class Solution {

    private int b_search(int[] nums, int low, int high, int num) {
        while( low <= high ) {
            int mid = ( low + high ) / 2;
            if( nums[mid] == num ) {
                return mid;
            } else if( nums[mid] > num ){
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return -1;
    }

    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        int len = nums.length;
        if( len < 3 ){
            return res;
        }
        Arrays.sort(nums);
        for(int i=0; i<len; i++) {
            if( i!=0 && nums[i-1]==nums[i] ) {
                continue;
            }
            int last = i+1;
            while( last < len-1 ) {
                if( last > i+1 && nums[last-1]==nums[last] ) {
                    last ++;
                    continue;
                }
                int num = nums[i] + nums[last];
                if( num > 0 ) {
                    break;
                }
                int ind = b_search(nums, last+1, len-1, num*-1);
                if( ind!=-1 ) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[last]);
                    list.add(nums[ind]);
                    res.add(list);
                }
                last ++;
            }
        }
        return res;
    }
}

双指针

点击查看代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        int lasta = -100005;
        int n = nums.length;
        Arrays.sort(nums);
        for(int i=0; i<n; i++) {
            int a = nums[i];
            if( lasta==a ) {
                continue;
            }
            lasta = a;
            int low = i+1;
            int high = n - 1;
            while( low < high ) {
                int sum = a + nums[low] + nums[high];
                if( sum>0 ) {
                    high --;
                } else if( sum < 0 ) {
                    low ++;
                } else {
                    List<Integer> list = new ArrayList<>();
                    list.add(a);
                    list.add(nums[low]);
                    list.add(nums[high]);
                    res.add(list);
                    while(low<high && nums[low]==nums[low+1]) {
                        low ++;
                    }
                    while(low<high && nums[high]==nums[high-1]) {
                        high --;
                    }
                    low ++;
                    high --;
                }
            }
        }
        return res;
    }
}
posted @ 2022-04-20 21:14  Asimple  阅读(16)  评论(0编辑  收藏  举报