三数之和 (简单易理解)
题意:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
难点:本题的难点在于如何去除重复解
使用方法:双指针
基本思路:固定一个位置,另外两个位置使用双指针去移动
执行步骤:
- 去掉特殊情况,对于数组长度小于3,数组为空的情况,直接返回 []
- 数组排序,按照从小到大排序(为了方便剪枝,去除重复情况)
- 遍历排序后的数组,此时的i即为固定位置,每次的遍历都是使用一次双指针
- 如果当前i指向的元素都大于0,则不可能出现=0的三个数了(因为数组是排序后的,当前i是三个数中的最小值)
- i遍历到重复元素则跳过,避免出现重复解
- 令左指针l=i+1,右指针r=n-1 (左指针指向当前遍历i的下一位;右指针指向最后,从后往前遍历),当l<r时 ,执行循环
- sum=nums[i]+nums[l]+nums[r],如果等于0,将结果对应的索引位置的值加入结果集中,别忘了此时要对左右指针去重、移位
- 如果结果sum大于0,将右指针左移
- 如果结果小于0,将左指针右移
可执行代码
class Solution():
def threeSum(self,nums):
n=len(nums)
result=[]
#如果数组为null或者长度小于3,返回[]
if nums==None or n<3:
return []
#对数组进行排序
nums.sort() #该方法没有返回值,但是会对列表的对象进行排序
#遍历排序后的数组
for i in range(n):
#如果当前i指向的元素都大于0,则不可能出现=0的三个数了
if nums[i]>0:
return result
# i 重复元素则跳过
if i > 0 and nums[i]==nums[i-1]:
continue
#令左指针l=i+1,右指针r=n-1
l=i+1
r=n-1
# 当l<r时 ,执行循环
while(l<r):
sum=nums[i]+nums[l]+nums[r]
# 如果等于0,将结果对应的索引位置的值加入结果集中
if sum==0:
result.append([nums[i],nums[l],nums[r]])
#在将左指针和右指针移动的时候,先对左右指针的值,进行判断; 如果重复,直接跳过;
#去重,因为 i 不变,当此时 l取的数的值与前一个数相同,所以不用在计算,直接跳
while l < r and nums[l]==nums[l+1]:
l+=1
#去重,因为 i不变,当此时 r 取的数的值与前一个相同,所以不用在计算
while l < r and nums[r]==nums[r-1]:
r-=1
#将 左指针右移,将右指针左移
l+=1
r-=1
# 如果结果大于0,将右指针左移
elif sum>0:
r-=1
#如果结果小于0,将左指针右移
else:
l+=1
return result
注意:
- 固定位置i和左右指针的去重操作不一样
固定位置: nums[i]==nums[i-1]
左指针: nums[l]==nums[l+1]
右指针: nums[r]==nums[r-1]
原因:这是因为固定位置去重时,如果使用nums[i]==nums[i+1],那么会导致丢失一些非重复的出现情况
例如:数组 [1,1,2]
使用nums[i]==nums[i+1]这种方式:在遍历第一个1时,会将后一个1判断为重复,直接跳过[1,1,2]这种情况;
使用nums[i]==nums[i-1]这种方式:在遍历第一个1时,不会将后一个1判断为重复,添加[1,1,2]这种情况到结果集
我们要做的是不能有重复的三元组,但三元组内的元素是可以重复的!