本题出自力扣,难度:中等
题目:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
需要注意,当数据量过大时超时的问题,参考大神们的解法,自己理解了一下,详细看注释
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
a = []
# 先排序
nums.sort()
# nums元素小于3,则不成立,直接返回[]
if len(nums) < 3:
return []
# 排序后,第一个元素大于0或者最后一个元素小于0,则肯定不成立,返回[]
if nums[0] > 0 or nums[-1] < 0:
return []
# 循环列表,最后两位元素就不用循环了(因为需要3个数相加)
# 现在假设,v是第一位数字,t是第二位数字的下标,j是第三位数字的下标
for k,v in enumerate(nums[:-2]):
# 如果元素大于0后,就跳出循环,因为后面的数大于0
if v > 0:
break
# 如果 k不等于0 而且 前一个元素等于现在的元素,就跳出此次循环
if k != 0 and nums[k-1] == v:
continue
# t是左边开始移动的数字(初始值为最左边第二位)
# j是右边开始移动的数字(初始值为最右边第一位)
t = k + 1
j = len(nums) - 1
# 当左边开始移动的数字小于右边开始移动的数字下标时循环
while t < j:
# 计算三位数字之和
s = v + nums[t] + nums[j]
# 如果三位数之和小于0,因为第一位数字在这个循环是固定的,就要找更大的数字,即最二位数字向右移(列表由小到大排序)
if s < 0:
t += 1
# 如果右移时,出现相同的数字,就要跳过(不用重复计算),且下标加一
while t < j and nums[t] == nums[t-1]:
t += 1
# 如果三位数之和大于0,因为第一位数字在这个循环是固定的,就要找更小的数字,即第三位数字向左移(列表由小到大排序)
elif s > 0:
j -= 1
# 如果左移时,出现相同的数字,就要跳过(不用重复计算),且下标加一
while t < j and nums[j] == nums[j+1]:
j -= 1
# 如果等于0,则加入a列表,因为单纯向右移动第二位(变大)或左移第三位(变小),三个数之和都会只会单纯的变大或变小,所以第二位向右移第三位向左移,同样,出现重复数字,则跳过且下标加一或减一
else:
a.append([v,nums[t],nums[j]])
t += 1
j -= 1
while t < j and nums[t] == nums[t-1]:
t += 1
while t < j and nums[j] == nums[j+1]:
j -= 1
return a
浙公网安备 33010602011771号