2023.7.10 最接近的三数之和
排序+二分
可以先对数组排序,这样就拥有了单调性,就可以在其上做二分。
首先枚举第一个数a,然后枚举第二个数b,此时与target的差值就是diff = abs(target - a - b)
。由于题目要求找最接近的,所以候选元素c有两种可能,一种是c <= diff
,一种是c > diff
。正好对应二分的两种情况,所以二分查找一下就行,时间复杂度是\(O(n^2logn)\)。
排序+双指针
可以用二分的题,通常都可以优化一下使用双指针。同样也是先排序,获得单调性。
枚举第一个数a,其下标为i,此时可以令b为i+1,c为n-1。此时的和sum = a + b + c
,如果该和sum > target
,那么令指向c的指针往前移动,如果sum < target
,令指向b的指针往后移动,如果sum = target
,直接返回答案。
对于每一个a都进行一次这样的双指针检验,所以是时间复杂度是\(O(n^2)\)。
impl Solution {
pub fn three_sum_closest(nums: Vec<i32>, target: i32) -> i32 {
let n = nums.len();
let mut nums = nums;
nums.sort();
let mut res = 0x3f3f3f3f;
let mut update = |cur: i32| {
if (cur - target).abs() < (res - target).abs() { res = cur; }
};
for i in 0..n-2 {
if i > 0 && nums[i] == nums[i - 1] { continue; }
let (mut j, mut k) = (i + 1, n - 1);
while j < k {
let sum = nums[i] + nums[j] + nums[k];
if sum == target { return target; }
update(sum);
if sum > target {
let mut dk = k - 1;
while j < dk && nums[dk] == nums[k] { dk -= 1; }
k = dk;
}
else {
let mut dj = j + 1;
while dj < k && nums[dj] == nums[j] { dj += 1; }
j = dj;
}
}
}
res
}
}