必刷100题之三数之和

题目链接

        15. 三数之和 - 力扣(LeetCode)

题目解析

        

        1> 选出的三元组里面的每个元素是不同位置的

        2> 三个数相加是0

        通过示例一我们可以知道

        3> 我们三元组是不能重复的(不管位置,说明我们需要去重)

        4> 三元组的顺序是不用管,内容不同就行(就可以进行排序了)

算法原理

        解法一: 

                先排序+暴力枚举+利用set去重

                时间复杂度: O(n^3)

        解法二:

                双指针+ 双指针

                对于有序数组,我们要想到二分算法和双指针算法(可以降阶)

                1> 排序

                2> 先固定一个a

                3> 在剩下的区间里面找俩个数之和为-a的数. 此时我们可以定义left和right来遍历剩下的区间(left从"头开始找,right从尾开始找)

                处理细节问题:

                1> 去重

                我们注意到,我们已经排好序了,那么结果一样的数已经被放在一起了

                比如下面的例子

                当我们的0和4已经找到结果和为4的值了,因为排好了顺序,那么我们就可以跳过后面重复的0和4了.

        同理i指向的元素也需要判断是否是重复元素

        当使用完一次双指针算法之和,i也需要跳过重复元素

        

                也就是找到一种结果之和,left和right指针要跳过重复的元素

                        去重: 1. 注意left和right的去重. 2. 注意i的去重

                        这里要注意,我们去重移动i,left,right的时候也要考虑越界的问题

                2> 不漏: 我们找到一个之后要继续寻找,不要停

                3> 当我们的a都为正数了就不需要去后面继续找下去,因为后面的数不可能有负数

        

编写代码

        

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //创建二维数组,每次i遍历完就加入
        List<List<Integer>> list = new ArrayList<>();
        //1. 先进行排序
        Arrays.sort(nums);
        //先进行第一层循环
        for(int i = 0;i < nums.length;){
            //2.用a来记录i指向的数
            int a = -nums[i];
            //判断a是不是负数
                if(a < 0){
                    break;
                }
            //设定left和right
            int left = i+1;
            int right = nums.length - 1;
            //3. 利用双指针算法来找到俩个和为-a的的数
            //第二层循环
            while(left < right){
                int sum = nums[left] + nums[right];
                if(sum < a && left < right){
                    left++;
                }else if(sum > a && left < right){
                    right--;
                }else{
                    //加入一维数组
                    list.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[left],nums[right])));
                    //缩小区间继续寻找
                    left++;
                    right--;
                //去重操作: left,right
                    while(nums[left] == nums[left-1] && left < right){
                    left++;
                    }
                    while(nums[right] == nums[right+1] && left < right){
                    right--;
                    }
                }
            }
            //去重i
            i++;
            while(i < nums.length && nums[i] == nums[i-1]){
                i++;
            }
        }
        return list;
    }
}

需要注意的地方

        我们的i进行去重操作是不能写在定义的时候的,需要操作完,找到了那一个阶段的元组之后才可以去重.

        Arrays.asList(....)这个函数可以直接就生成指定数的列表

                

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值