leetcode刷题---热门百题---三数之和

给你一个包含 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]
输出:[]

提示:

0 <= nums.length <= 3000
-105 <= nums[i] <= 105

一开始做这题的时候是没啥思路的,看了题解的提示双指针也没想到具体怎么应用,然后完整理解题解之后感觉醍醐灌顶
解题思路:

暴力法搜索为 O(N3)O(N^3)O(N3) 时间复杂度,可通过双指针动态消去无效解来优化效率。
双指针法铺垫: 先将给定 nums 排序,复杂度为 O(NlogN)O(NlogN)O(NlogN)。
双指针法思路: 固定 333 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引 (k,len(nums))(k, len(nums))(k,len(nums)) 两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足 nums[k] + nums[i] + nums[j] == 0 的 i,j 组合:
    当 nums[k] > 0 时直接break跳出:因为 nums[j] >= nums[i] >= nums[k] > 0,即 333 个数字都大于 000 ,在此固定指针 k 之后不可能再找到结果了。
    当 k > 0且nums[k] == nums[k - 1]时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合。
    i,j 分设在数组索引 (k,len(nums))(k, len(nums))(k,len(nums)) 两端,当i < j时循环计算s = nums[k] + nums[i] + nums[j],并按照以下规则执行双指针移动:
        当s < 0时,i += 1并跳过所有重复的nums[i];
        当s > 0时,j -= 1并跳过所有重复的nums[j];
        当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。
复杂度分析:
    时间复杂度 O(N2)O(N^2)O(N2):其中固定指针k循环复杂度 O(N)O(N)O(N),双指针 i,j 复杂度 O(N)O(N)O(N)。
    空间复杂度 O(1)O(1)O(1):指针使用常数大小的额外空间。

作者:jyd
链接:https://leetcode-cn.com/problems/3sum/solution/3sumpai-xu-shuang-zhi-zhen-yi-dong-by-jyd/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这里复制过来有乱码,理解意思即可
下面是代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        //先对nums进行排序
        Arrays.sort(nums);

        for(int k = 0;k < nums.length - 2;k++){
            //如果现在指针指向的k已经大于0,那么三者相加一定不为0,直接跳出循环
            if(nums[k] > 0)break;
            //如果当前的k和上一个k数值相等,那么就跳到下一个k
            if(k > 0 && nums[k] == nums[k-1])continue;
            //i从k的下一个开始遍历,j从最后开始遍历
            int i = k + 1,j = nums.length - 1;

            while(i < j){
            //计算当前情况下不变指针k和双指针i,j的合
                int sum = nums[k] + nums[i] + nums[j];
   
                if(sum < 0){//小于零说明i太小了,所以i往后移动
                //这里的while会一直循环直到找到下一个i
                    while(i < j && nums[i] == nums[++i]);
                }else if(sum > 0){//大于零说明j太大了,所以j往前移动
                    while(i < j && nums[j] == nums[--j]);
                }else{//此时相加为0
                //将此时的数组内容添加进答案的list中
                    ans.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
                    //同时i向后移动以及j向前移动,避免出现重复
                    while(i < j && nums[i] == nums[++i]);
                    while(i < j && nums[j] == nums[--j]);
                }
            }
        }
        return ans;

    }
}

这里中值得学习的还有Arrays的用法,可以用sort来排序以及asList来给数据变成list集合

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值