15、三数之和

问题描述

在这里插入图片描述

问题分析

分析题目,使用3个变量i、j、k暴力求解显然是不太现实的,想都不用想肯定超时。思考一番后,觉得可以改为a+b=-c,即固定一个数,移动另外两个数,这样将时间复杂度降到O(n^2)。并且,可以使用对撞指针提高性能。此题难点在去除重复的三元组,考虑了半天,最后还是老老实实用指针来去除重复三元组。

算法思路如下:

  1. 先对数组进行排序。数组被分为小于0、等于0、大于0三部分。
  2. 首先外层使用一层循环,first指针从左往右(从小到大)扫描,一直到0为止(包含0)。扫描过程中,first指针不动,对于first指针右边的剩余数组采用对撞指针的形式,i、j分别表示剩下的两个数的指针。
  3. 显然,若nums[i] + nums[j] + nums[first] == 0,则表示找到一个解。若nums[i] + nums[j] + nums[first] > 0,则表示i和j所指元素的和太大了,则让j–,这样两者的和就变小了。反之,i++,使两者的和变大。
  4. 经过如上步骤,可以找到所有解。但是其中有很多重复解。重复解的造成主要是因为数组中有很多重复数字,对于这种情况,我的解决方法是:通过指针解决,即,每次移动指针时,不是仅仅i++就够了,而是遇到重复数字继续++,直到遇到不相同的数字为止。

解法:对撞指针

  • 时间复杂度:O( n2 ),其中n表示数组的长度。

Java代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> results = new ArrayList<>();
        Arrays.sort(nums);
        for (int first = 0; (nums.length >= 3) && (nums[first] <= 0) && (first < nums.length-2); first++) {
            //与前一个first所对的数字不重复
            if (!(first > 0 && nums[first] == nums[first-1])){
                int i = first + 1;
                int j = nums.length - 1;
                while (i < j){
                    if (nums[i] + nums[j] + nums[first] == 0){
                        List<Integer> result = new ArrayList<>();
                        result.add(nums[first]);
                        result.add(nums[i]);
                        result.add(nums[j]);
                        results.add(result);
                        //去重(与前一个i或者j所对的数字不重复)
                        do {
                            i++;
                        }while (i > 0 && i < j && nums[i] == nums[i-1]);

                        do {
                            j--;
                        }while (j < nums.length-1 && i < j && nums[j] ==  nums[j+1]);


                    } else if (nums[i] + nums[j] + nums[first] > 0){
                        do {
                            j--;
                        }while (j < nums.length-1 && i < j && nums[j] ==  nums[j+1]);
                    } else {
                        do {
                            i++;
                        }while (i > 0 && i < j && nums[i] == nums[i-1]);

                    }

                }
            }

        }
        return results;
     }
}

结果分析

以上代码的执行结果:

执行时间内存消耗
106ms56.7MB

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值