本题出自力扣,难度:中等
题目:
给你一个包含 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