【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
相关推荐
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼3 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
m0_547486663 天前
《数据结构教程》全套 PPT课件2026
数据结构
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark3 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法