刷题使我快乐,满脸开心.jpg
- 来源:力扣(LeetCode)
- 链接:https://leetcode.cn/problems/3sum-closest/
- 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目
给你一个长度为 n
的整数数组 nums
和 一个目标值 target
。请你从 nums
中选出三个整数,使它们的和与 target
最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例 1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:
输入:nums = [0,0,0], target = 1
输出:0
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-10^4 <= target <= 10^4
思路
这道题先对还是比较简单的,最关键有两个思路
- 先排序。这个是时间优化最大的,没有排序,就无法很好的完成剪枝
- 双指针。如果还是三层循环,无论如何剪枝,也是在
O(N^2)
复杂度之上,所以需要敲掉一层循环。而在确定一个元素 + 已经排序
的基础上,利用双指针双向移动寻找结果
,就变成了一个很好的降低复杂度的方法
其他的没有什么可说的了,上代码吧
代码
func threeSumClosest(nums []int, target int) int {
// 先排序,便于处理
sort.Ints(nums)
n := len(nums)
// 两种特殊情况快速返回
if nums[0]+nums[1]+nums[2] >= target {
return nums[0] + nums[1] + nums[2]
} else if nums[n-1]+nums[n-2]+nums[n-3] <= target {
return nums[n-1] + nums[n-2] + nums[n-3]
}
// 赋个初始值。或者直接 10^4 + 1000*3
res := nums[0] + nums[1] + nums[2]
if abs(nums[n-1]+nums[n-2]+nums[n-3]-target) < res {
res = nums[n-1] + nums[n-2] + nums[n-3]
}
// 再往右就没有左右指针位置了,所以只到 n-3
for i := 0; i < n-2; i++ {
// 相同元素可以跳过,所有情况会被之前的数字包含
if i > 0 && nums[i] == nums[i-1] {
continue
}
// 左右指针
l, r := i+1, n-1
for l < r {
sum := nums[i] + nums[l] + nums[r]
// 恰好相等是最优解,不用再找了
if sum == target {
return sum
}
// 看差值绝对值大小
if abs(sum-target) < abs(res-target) {
res = sum
}
if sum < target {
l++
// 跳过相同元素
for l < r && nums[l] == nums[l-1] {
l++
}
} else {
r--
// 跳过相同元素
for l < r && nums[r] == nums[r+1] {
r--
}
}
}
}
return res
}
func abs(a int) int {
if a < 0 {
return -a
}
return a
}