题目:
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != 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 ],与预期输出一致。
逻辑梳理:
-
排序数组 首先对数组进行排序,这样可以方便地使用双指针技术,并且便于跳过重复值。
-
数组长度判断 如果数组长度小于3,直接返回空列表,因为无法组成三元组。
-
遍历第一个指针
ii的取值范围是0到n - 3,因为需要给j和k留出空间。 -
跳过重复值 如果
i > 0且当前元素与前一个元素相同,则跳过当前i,避免重复结果。 -
提前终止条件
-
如果当前元素与后两个最小元素之和大于0,说明后续不可能有解,直接跳出循环。
-
如果当前元素与最大的两个元素之和小于0,说明当前元素太小,无法组成和为0的三元组,跳过。
-
-
双指针查找
-
j从i + 1开始,k从数组末尾开始。 -
计算三数之和
sums,根据sums的值调整指针位置:-
如果
sums > 0,说明需要减小数值,移动k左移。 -
如果
sums < 0,说明需要增大数值,移动j右移。 -
如果
sums == 0,找到一个解,将其加入结果列表,并跳过重复的j和k值。
-
-
&spm=1001.2101.3001.5002&articleId=146551166&d=1&t=3&u=e66393a7eefd4cf3bb7b9ad18ff5844e)
2048

被折叠的 条评论
为什么被折叠?



