【Leetcode】三数之和

1 题目

给你一个整数数组 nums ,判断是否存在三元组 nums\[i, numsj, numsk] 满足 i != j、i != k 且 j != k ,同时还满足 numsi + numsj + numsk == 0 。请你返回所有和为 0 且不重复的三元组。

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

示例 1:

输入:nums = -1,0,1,2,-1,-4

输出:\[-1,-1,2,-1,0,1]

解释:

nums0 + nums1 + nums2 = (-1) + 0 + 1 = 0 。

nums1 + nums2 + nums4 = 0 + 1 + (-1) = 0 。

nums0 + nums3 + nums4 = (-1) + 2 + (-1) = 0 。

不同的三元组是 -1,0,1 和 -1,-1,2 。

注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = 0,1,1

输出:\[\]

解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = 0,0,0

输出:\[0,0,0]

解释:唯一可能的三元组和为 0 。

2 分析

这道题乍一看最直观的解法是三重遍历,但时间复杂度是O(N^3),而且无法解决重复的问题。因此,进阶解法需要解决以下两个问题:

  • 时间复杂度
  • 重复元素

通过对数组排序,可以将相同的元素放到一起,且单调数组更容易做推断。接下来,只需要固定元素numsi,寻找j和k使得numsj+numsk=-numsi即可。让left和right指针分别指向数组左边的小元素和右边的大元素,基于单调性,如果numsleft+numsright<-numsi,只需要将left右移,就可以得到更大的和;如果如果numsleft+numsright>-numsi,只需要将right左移,就可以得到更小的和。这样只需要两层遍历。

另一个问题是怎么解决重复元素?只需要当前位置与前一个位置比较,如果相同则跳过。这里分三种情况,

  • 第一种情况是固定位置numsi,只需要比较每个循环中numsi与前一个位置numsi-1是否相等,如果相等则不需要再做循环,直接continue即可。
  • 第二种情况是left指针位置,当找到满足要求的三元组后,left指针会加一,right指针会减一,因此需要比较numsleft与前一个位置numsleft-1是否相等,如果相等则继续对left加一,直到left不比right小;
  • 第三种情况是right指针位置,也是在找到满足要求的三元组之后,需要比较numsright与后一个位置numsright+1是否相等,如果相等则继续对right减一,直到right不比left大。

从时间复杂度上看,排序复杂度O(n log n) ,后续双层遍历复杂度O(n²)。根据大O表示法,O(n log n + n²) = O(n²)。因此时间复杂度为O(n²)。

3 代码

python 复制代码
def threeSum(self, nums):
    """
    :type nums: List[int]
    :rtype: List[List[int]]
    """
    nums.sort()
    n = len(nums)
    res = []
    for i in range(n-1):
        if i>0 and nums[i]==nums[i-1]:
            continue
        target = -nums[i]
        left, right = i+1, n-1
        while left < right:
            cur_sum = nums[left] + nums[right]
            if  cur_sum == target:
                res.append([nums[i], nums[left], nums[right]])
                left += 1
                right -= 1
                while left<right and nums[left] == nums[left-1]:
                    left +=1
                while left<right and nums[right]== nums[right+1]:
                    right -= 1
            elif cur_sum > target:
                right -= 1  
            else:
                left += 1
    return res
相关推荐
leobertlan5 小时前
痛苦系列 | DSP-03 跨越单位圆:Z变换与零极点分析
算法·程序员
蛋蛋的就会顺顺的5 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
开发小能手1236 小时前
答案daanC语言
数据结构·算法
Navigator_Z7 小时前
LeetCode //C - 1291. Sequential Digits
c语言·算法·leetcode
pride.li9 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
旺仔仔仔9 小时前
机器人项目实战(5):从单次抓取,到接收指令连续做事
算法
旺仔仔仔9 小时前
机器人项目实战(2):识别物体、提取点云,再到抓取姿态
算法
姜鱼问生10 小时前
密码明明一样,为什么 GPG 说“错的“?
后端·算法·架构
启观川10 小时前
数据结构与算法-第 3 章 常用算法-贪心算法
数据结构·笔记·python·算法·贪心算法
对空六课10 小时前
指标口径生效时间的版本查询实现
大数据·服务器·前端·算法·数据分析