leetcode15---三数之和

leetcode15—三数之和

关键词:双指针 排序

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum

解法—双指针

动画说明见 这里

先对数组进行排序方便比较,因为题目要求的数而不是下标所以可以进行排序。

  • 在遍历数组的过程中,对每个数 i 定义一个left指针和right指针。
  • 固定i,根据三者的和对left和right进行移动,
  • 当left超过right退出,移动 i 并定义新的left指针和right指针。

同时还要考虑重复数字的情况,因此移动的时候要移动到一个新的数的位置。不然会产生相同的解,不满足题意。

代码

 // 快速排序
function sortarray(nums) {
    function fastsort(low, high) {
        if (low>=high) return 
        let mid = low;
        for (let i=low+1; i<=high; i++){
            if (nums[i] < nums[mid]) {
                let temp = nums[i];
                nums[i] = nums[mid];
                nums[mid] = temp;
                ++mid;
                temp = nums[mid];
                nums[mid] = nums[i];
                nums[i] = temp;
            }
        }
        fastsort(low, mid-1);
        fastsort(mid+1, high);
    }
    if (nums.length<=1) return nums
    fastsort(0, nums.length-1);
    return nums;
}



var threeSum = function(nums) {
    if (nums.length<3) return [];
    nums = sortarray(nums);
    res = [];
    let left, right;
    for (let i=0; i<nums.length-2; i++) {
        // i大于0表示三个数都大于0,因此和不可能为0
        if (nums[i]>0) break;
        // i对应数与上一个相同的话跳过
        // 特殊情况是有三个0,通过i大于等于1使数组只有三个零时正常执行
        // 与之前的相同跳过使得相同情况下也起码会执行一轮判断
        if (i>=1 && nums[i] == nums[i-1]) continue;
        left = i+1;
        right = nums.length - 1;
        while (left<right) {
            target = nums[i] + nums [left] + nums[right];
            if (target==0) {
                res.push([nums[i], nums[left], nums[right]]);
                // 处理重复情况 避免相同解两侧都要进行移动
                // 因为上一组刚好为0了,所以在无重复解而且i固定的前提下,移动一个数无法获得满足题意的解
                // 必须要两边都进行移动
                while (left<right && nums[left]==nums[left+1]) ++left;
                while (left<right && nums[right]==nums[right-1]) --right;
                --right;
                ++left;

            }
            else if (target > 0) {
                // 处理重复情况
                while (left<right && nums[right]==nums[right-1]) --right;
                --right;
            }
            else {
                // 处理重复情况
                while (left<right && nums[left]===nums[left+1]) ++left;
                ++left;
            }
        }
    }
    return res;
};

这里练习了一下快速排序,已经有点生疏了。

代码的流程用注释进行了解释。

一些优化处理:

// i大于0表示三个数都大于0,因此和不可能为0
if (nums[i]>0) break;

同时不能忘记 i 自身的迭代也会重复:

 // i对应数与上一个相同的话跳过
 // 特殊情况是有三个0,通过i大于等于1使数组只有三个零时正常执行
 // 与之前的相同跳过使得相同情况下也起码会执行一轮判断
 if (i>=1 && nums[i] == nums[i-1]) continue;

又要考虑三个零也能满足题意的情况,加上i大于等于1并与前一个比较的条件。

移动时也要注意在三数之和等于0时,要同时移动左右指针,因为只移动一个会明显不相等因此两个都要移动。

// 处理重复情况 避免相同解两侧都要进行移动
// 因为上一组刚好为0了,所以在无重复解而且i固定的前提下,移动一个数无法获得满足题意的解
// 必须要两边都进行移动
while (left<right && nums[left]==nums[left+1]) ++left;
while (left<right && nums[right]==nums[right-1]) --right;
--right;
 ++left;

外层的移动是因为内部的while循环还不足以移动到新的数字,会停在前一位,因此还需再移动一次。

复杂度分析

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2), for循环时间复杂度是 O ( n ) O(n) O(n),while循环也是 O ( n ) O(n) O(n)
  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),不考虑返回答案的数组的空间,排序使用的空间是 O ( log ⁡ n ) O(\log n) O(logn),如果不能在原数组上修改的话,则排序到新的数组的复杂度就是 O ( n ) O(n) O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值