Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]]
二、思路分析
- 三数之和是两数之和的后续题目,首先考虑暴力方式解决此题,由于要枚举三个数,暴力方式的时间复杂度为O(n3)。考虑到需要去除重复的结果,对数组进行排序,使用内置的快排
sort.Ints函数,并且在每层循环中加入nums[x]==nums[i-1] { continue }避免重复。 - 一种更有效率的方式是,将第三层k循环改变为双指针的方式,即枚举第二个数和第三个数的时候为两个指针,一个正向遍历,一个从后向前。这样复杂度降低为O(n),第一个指针向后移动时,后一个指针向前移动,即可遍历到符合条件的结果,两层的遍历总共会遍历O(n)的时间复杂度,当两个相同时使其跳出循环,即代码中
j == k { break }
三、AC 代码
暴力破解
func threeSum(nums []int) (ans [][]int) {
sort.Ints(nums)
for i := 0;i<len(nums);i++ {
//去重
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j := i+1 ;j<len(nums);j++ {
if j > i + 1 && nums[j] == nums[j-1] {
continue
}
for k := j + 1 ;k<len(nums);k++ {
if k > j +1 && nums[k] == nums[k-1]{
continue
}
if nums[j] + nums[k] + nums[i] == 0 {
ans = append(ans,[]int{nums[i],nums[j],nums[k]})
}
}
}
}
return ans
}
双指针做法
func threeSum(nums []int) (ans [][]int) {
sort.Ints(nums)
for i := 0;i<len(nums);i++ {
//去重
if i > 0 && nums[i] == nums[i-1] {
continue
}
k := len(nums) - 1
for j := i+1 ;j<len(nums);j++ {
//去重
if j > i + 1 && nums[j] == nums[j-1]{
continue
}
//k在最右边
for j < k && nums[j] + nums[k] +nums[i] > 0 {
k--
}
if j == k {
break
}
if nums[j] + nums[k] + nums[i] == 0 {
ans = append(ans,[]int{nums[i],nums[j],nums[k]})
}
}
}
return ans
}
四、总结
当需要枚举数组中两个元素时,第一个元素递增,第二个元素递减时,就可以考虑双指针做法。如本题中,枚举的第一个数是确定的,目标值也是确定的,则第二个数和第三个数一个增加另一个就要递减。