【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
相关推荐
YouonlyliveonceC12 分钟前
《大话数据结构》第4章实战:中缀表达式转后缀 + 后缀表达式求值(完整可运行实现)
算法
phoenix@Capricornus21 分钟前
从统计决策到贝叶斯估计
人工智能·算法·机器学习
AICDragon29 分钟前
1.8%就够了:K3的896个MoE专家,为什么激活率这么低反而是好事?
人工智能·算法
VALENIAN瓦伦尼安教学设备1 小时前
ASHOOTER激光对中仪如何通过颜色确定调整是否合适
数据库·嵌入式硬件·算法
货拉拉技术1 小时前
重塑 Agent 度量衡:基于 LLM-as-a-Judge 的离线评估体系与实践
算法·设计模式
车压1 小时前
从“为什么”理解注意力机制
算法
wabs6661 小时前
关于哈希表【力扣15.三数之和的思考】
数据结构·算法·leetcode·散列表·哈希表·三数之和
退休倒计时1 小时前
【每日一题】LeetCode 88. 合并两个有序数组 TypeScript
算法·leetcode·职场和发展·typescript
键盘会跳舞1 小时前
C++:函数对象与 std::function 源码级深度拆解——泛型算法的策略内核与可调用对象统一封装
c++·算法·仿函数
手写码匠2 小时前
华为云Flexus+DeepSeek征文|Agent 评测体系实战:用 DeepSeek-R1 当裁判,打造 Dify Agent 的自动化回归测试流水线
人工智能·深度学习·算法·aigc