15. 三数之和 - 力扣(LeetCode)

Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

题目:

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

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-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 。

提示:

  • 3 <= nums.length <= 3000

  • -105 <= nums[i] <= 105


思路如下:

        这道题要求从整数数组内选取三个数,使得相加为 0 ,找出所有符合条件的三元组。要求不可以包含重复的三元组,并且输出的顺序和三元组的顺序并不重要。

        所以我们要自己确定一个查找规则,将数组元素进行 nus.sort() 升序处理。这里运用三指针的思想, i 指针遍历整个数组(跳过 j k 的位置),j 指针从 i + 1向后遍历,k 从 末向前。因为不能重复,当遇到重复元素时跳过,按下方题解进行遍历......直到找到所有不重复且符合条件的三元组。


题解如下:

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        res = []  # 存储结果的列表
        nums.sort()  # 对数组进行 升序 排序
        
        # 如果数组长度小于3,直接返回空列表
        if n < 3:
            return res
        
        for i in range(n - 2): # 左闭右开,遍历到 n - 3 ,为了给 j k 留空间
            
            # 如果当前元素与前一个元素相同,跳过(避免重复结果)
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            
            j = i + 1  # j 指针从 i 的下一个位置开始
            k = n - 1  # k 指针从数组末尾开始
            
            while j < k:
                sums = nums[i] + nums[j] + nums[k]  # 计算当前三数之和
                
                # 如果和大于0,说明需要减小数值,移动 k 指针左移
                if sums > 0:
                    k -= 1
                # 如果和小于0,说明需要增大数值,移动 j 指针右移
                elif sums < 0:
                    j += 1
                else:
                    res.append([nums[i], nums[j], nums[k]])  # 将解加入结果列表
                    
                    # 跳过重复的 j 值
                    j += 1
                    while j < k and nums[j] == nums[j - 1]:
                        j += 1
                    
                    # 跳过重复的 k 值
                    k -= 1
                    while k > j and nums[k] == nums[k + 1]:
                        k -= 1
        
        return res

题解示例:

# 输入数组和预期输出 #
输入数组:[-1, 0, 1, 2, -1, -4]
预期输出:[[ -1, -1, 2 ], [ -1, 0, 1 ]]
​
排序数组
首先对数组进行排序,得到:[-4, -1, -1, 0, 1, 2]
遍历第一个指针 i
从 i = 0 开始,逐步移动到 i = n - 3(因为要给 j 和 k 留出空间)。
​
处理重复值
如果 i > 0 且 nums[i] == nums[i - 1],则跳过当前 i,避免重复结果。
​
初始化双指针 j 和 k
j 初始化为 i + 1,k 初始化为数组末尾索引 n - 1。
​
双指针查找
在 j < k 的条件下,计算三数之和 sums = nums[i] + nums[j] + nums[k],并根据 sums 的值调整指针位置:
如果 sums > 0,说明当前和太大,需要减小 k。
如果 sums < 0,说明当前和太小,需要增大 j。
如果 sums == 0,说明找到一个满足条件的三元组,将其加入结果列表,并跳过重复的 j 和 k 值。
​
​
# 具体步骤示例 #
第一次循环 (i = 0)
nums[i] = -4
计算最小可能和:nums[i] + nums[i+1] + nums[i+2] = -4 + (-1) + (-1) = -6 < 0,继续。
计算最大可能和:nums[i] + nums[-1] + nums[-2] = -4 + 2 + 1 = -1 < 0,说明无法找到和为0的组合,直接跳过。
​
第二次循环 (i = 1)
nums[i] = -1
计算最小可能和:-1 + (-1) + 0 = -2 < 0,继续。
计算最大可能和:-1 + 2 + 1 = 2 > 0,说明可能存在和为0的组合。
初始化 j = 2,k = 5。
进入 while j < k 循环:
sums = -1 + (-1) + 2 = 0,满足条件,加入结果。
跳过重复的 j 和 k,移动指针。
j 移动到3,k 移动到4。
sums = -1 + 0 + 1 = 0,满足条件,加入结果。
跳过重复的 j 和 k,移动指针。
循环结束。
​
第三次循环 (i = 2)
nums[i] = -1,与前一个值相同,跳过。
​
第四次循环 (i = 3)
nums[i] = 0
计算最小可能和:0 + 1 + 2 = 3 > 0,说明无法找到和为0的组合,直接跳出循环。
​
最终结果
经过上述步骤,结果列表 res 中包含两个三元组:[ -1, -1, 2 ] 和 [ -1, 0, 1 ],与预期输出一致。

逻辑梳理:

  1. 排序数组 首先对数组进行排序,这样可以方便地使用双指针技术,并且便于跳过重复值。

  2. 数组长度判断 如果数组长度小于3,直接返回空列表,因为无法组成三元组。

  3. 遍历第一个指针 i i 的取值范围是 0n - 3,因为需要给 jk 留出空间。

  4. 跳过重复值 如果 i > 0 且当前元素与前一个元素相同,则跳过当前 i,避免重复结果。

  5. 提前终止条件

    • 如果当前元素与后两个最小元素之和大于0,说明后续不可能有解,直接跳出循环。

    • 如果当前元素与最大的两个元素之和小于0,说明当前元素太小,无法组成和为0的三元组,跳过。

  6. 双指针查找

    • ji + 1 开始,k 从数组末尾开始。

    • 计算三数之和 sums,根据 sums 的值调整指针位置:

      • 如果 sums > 0,说明需要减小数值,移动 k 左移。

      • 如果 sums < 0,说明需要增大数值,移动 j 右移。

      • 如果 sums == 0,找到一个解,将其加入结果列表,并跳过重复的 jk 值。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值