问题描述
给你一个整数数组 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
思路分析
- 首先对数组进行排序,将数组从小到大排序,以便后续操作。
- 初始化一个空列表 res,用于存储符合条件的三元组结果。
- 开始遍历数组,以每个元素 nums[i] 作为基准。
- 在每次遍历中,使用两个指针 left 和 right 分别指向当前元素 nums[i] 的下一个元素和数组的最后一个元素。
- 在 left < right 的条件下,进行循环:
- 计算三个数的和 total = nums[i] + nums[left] + nums[right]。
- 如果 total 等于 0,说明找到了满足条件的三元组,将其加入结果列表 res 中。
- 进一步避免重复计算:如果左指针所指的元素与下一个元素相等,则将左指针右移一位,直到不相等为止;同理,如果右指针所指的元素与前一个元素相等,则将右指针左移一位,直到不相等为止。
- 将左指针右移一位,将右指针左移一位。
- 如果 total 小于 0,说明三个数之和偏小,将左指针右移一位。
- 如果 total 大于 0,说明三个数之和偏大,将右指针左移一位。
- 返回结果列表 res。
代码分析
- 将数组进行排序,以方便后续的操作。
- 初始化一个空列表 res ,用于存储结果。
- 开始遍历数组,以每个元素 nums[i] 作为基准。
- 如果当前元素与前一个元素相等,则跳过,以避免重复计算。
- 初始化指针 left = i + 1 和 right = n - 1,其中 n 是数组的长度。
- 在 left < right 的条件下,进行循环:
- 计算三个数的和 total = nums[i] + nums[left] + nums[right]。
- 如果 total 等于 0,说明找到了满足条件的三元组,将其加入结果列表 res 中。
- 进一步避免重复计算:如果左指针所指的元素与下一个元素相等,则将左指针右移一位,直到不相等为止;
- 同理,如果右指针所指的元素与前一个元素相等,则将右指针左移一位,直到不相等为止。
- 将左指针右移一位,将右指针左移一位。
- 如果 total 小于 0,说明三个数之和偏小,将左指针右移一位。
- 如果 total 大于 0,说明三个数之和偏大,将右指针左移一位。
- 返回结果列表 res。
完整代码
class Solution(object):def threeSum(self, nums):# 对数组进行排序nums.sort()n = len(nums)res = []# 遍历数组,以每个元素 nums[i] 作为基准for i in range(n):# 如果当前元素与前一个元素相等,则跳过,以避免重复计算if i > 0 and nums[i] == nums[i-1]:continue# 初始化指针 left 和 rightleft = i + 1right = n - 1# 在 left < right 的条件下,进行循环while left < right:# 计算三个数的和 totaltotal = nums[i] + nums[left] + nums[right]# 如果总和等于 0,说明找到了满足条件的三元组if total == 0:# 将三元组加入结果列表 resres.append([nums[i], nums[left], nums[right]])# 进一步避免重复计算:将左指针右移一位,直到不与下一个元素相等while left < right and nums[left] == nums[left+1]:left += 1# 进一步避免重复计算:将右指针左移一位,直到不与前一个元素相等while left < right and nums[right] == nums[right-1]:right -= 1# 将左指针右移一位,将右指针左移一位left += 1right -= 1# 如果总和小于 0,将左指针右移一位elif total < 0:left += 1# 如果总和大于 0,将右指针左移一位else:right -= 1# 返回结果列表 resreturn res
详细分析
nums.sort()
:对输入的数组nums
进行原地排序,使其按照升序排列。n = len(nums)
:获取数组nums
的长度,即元素个数。res = []
:创建一个空列表res
,用于存储符合条件的三元组结果。for i in range(n):
:遍历数组nums
,以每个元素nums[i]
作为基准。if i > 0 and nums[i] == nums[i-1]: continue
:如果当前元素与前一个元素相等,则跳过循环,以避免重复计算。left = i + 1
:初始化指针left
,指向当前元素的下一个位置。right = n - 1
:初始化指针right
,指向数组的最后一个元素。while left < right:
:在left < right
的条件下,进行循环。total = nums[i] + nums[left] + nums[right]
:计算三个数的和total
。if total == 0:
:如果总和等于 0,说明找到了满足条件的三元组。- 将三元组
[nums[i], nums[left], nums[right]]
加入结果列表res
。 - 进一步避免重复计算:将左指针右移一位,直到不与下一个元素相等。
- 进一步避免重复计算:将右指针左移一位,直到不与前一个元素相等。
- 将左指针右移一位,将右指针左移一位。
- 将三元组
elif total < 0:
:如果总和小于 0,将左指针右移一位。else:
:如果总和大于 0,将右指针左移一位。return res
:返回结果列表res
。
运行效果截图
调用示例
solution = Solution()
nums = [-1,0,1,2,-1,-4]
nums1 = [0,1,1]
print(solution.threeSum(nums))
print(solution.threeSum(nums1))