双指针解法:
原理见注释
# 2025/6/6 9:40
# -*- coding:UTF-8 -*-
nums = [-1, 0, 1,1, 2, -1, -4,0,2,1,-3,4,10,-9]
def three_sum(nums):nums.sort()n = len(nums)result = []for i in range(n-2):# n-2,此时i取值到n-2-1,即倒数第3个数,此时才能保证倒数第3,倒数第2,倒数第1组成三个数的元组if i > 0 and nums[i] == nums[i-1]:continue# left right指针初始值:i+1,最后一个元素left, right = i+1, n-1while left < right:total = nums[i] + nums[left] + nums[right]# 如果和小于0,i不变,只能将left右移,因为已经排序了,往右的值会更大if total < 0:left += 1# 如果和大于0,i不变,只能将right左移,因为已经排序了,往左的值会更小elif total > 0:right -= 1# 等于0 直接加在result尾部else:result.append([nums[i], nums[left], nums[right]])# 一直到运行到此处往上,已经尝试了3个数字,需要再移动指针了,但在移动之前需要做一步去重操作,# 比如说nums=[1,2,2,3,-4]已经尝试了1,2,-4,和小于0,则需要移动left指针,即left指针下标加1,但下标加1后元素仍然是2# 所以没啥意义,需要去重,下标+1,至于移动的操作在去重完后统一加减。注意此处的+-1和while后+-1的区别while left < right and nums[left] == nums[left + 1]:left += 1while left < right and nums[right] == nums[right - 1]:right -= 1# 这里就是上述的统一加减的地方,也就是下一个循环的地方left += 1right -= 1return resultre = three_sum(nums)
print(re)
运行结果:
E:\TestData\suanfa\venv\Scripts\python.exe E:/TestData/suanfa/threesum.py
[[-9, -1, 10], [-4, 0, 4], [-4, 2, 2], [-3, -1, 4], [-3, 1, 2], [-1, -1, 2], [-1, 0, 1]]Process finished with exit code 0