时间复杂度:
解题思路
由于会有重复数字出现,而答案要求不重复,所以考虑对数组排序,再配合双指针算法,可以很好地解决重复问题。
题目要求三数之和为0,所以数组排序后搭配双指针还可以保证两数之和尽量接近于0。总体思路就是先对数组从小到大排序,然后从头开始选取一个元素left,对它右侧的所有元素使用双指针遍历来判断是否有两数之和为left的相反数(保证三数之和为0),如果两数之和大于目标数就令右指针左移,直至两指针碰撞或两数之和为left 的相反数。
为了保证不重复,需要在两处进行去重:一是从头开始遍历left时,如果遇到与上一个元素相同的情况就应该去重,去遍历下一个元素;二是在左指针右移时,如果元素与上一个元素相同,就应该去重。
AC代码
func threeSum(nums []int) (res [][]int) {
sort.Ints(nums)
n:=len(nums)
//left是三个数最小的那个数的索引
for left:=0;left<n;left++{
//去重
if left>0&&nums[left]==nums[left-1]{
continue
}
target:=0-nums[left]
right:=n-1
//mid是三数中中间数的索引
for mid:=left+1;mid<right;mid++{
//去重
if mid>left+1&&nums[mid]==nums[mid-1]{
continue
}
//三数和大于0,右指针左移寻找较小数
for mid<right&&nums[mid]+nums[right]>target{
right--
}
//三数之和为0
if mid!=right&&nums[mid]+nums[right]==target{
res=append(res,[]int{nums[left],nums[mid],nums[right]})
}
}
}
return res
}
感悟
遇到重复数字时,可以考虑先对数组排序。
涉及到这种多数求和时,可考虑双指针搭配排序解题。
二刷感悟
第一次的思路是遍历所有中间数,从两边向中间尝试。这一次的思路仿照官方题解,先固定最小的数,然后用双指针遍历所有比它大的数,实现过程中要注意两处去重。