leecode16 最接近的三数之和

在这里插入图片描述

我的思路

这个题难度不大,参考这个📄((20250730120638-7fmtj3w ‘0015 三数和’)),((20250728094651-r58pb04 ‘0001 两数之和’)) ,((20250730131645-jdjxatg ‘0167 两数之和II-输入有序数组’))

这个题相比之前的区别在于这个是和与target最接近。

难点在于我们应该什么时候移动这个j和k

  • 先排序,排序之后,就可以更方便的使用双指针了
  • 先用y来表示三者的和与target的插值
    如果为0代表这个就是最接近的,可以直接返回了
    如果大于0,代表这个target比较大,所以我们要让这三者的和增大一点,移动左边的指针
    如果小于0,代表这个target比较小,所以我们要让这三者的和减少一点,移动右边的指针
int n = nums.length;
Arrays.sort(nums);
int min = 100001;
int ans = 0;
for(int i = 0;i<n-2;i++){
    //确定的第一个数
    int x = nums[i];
    int j = i+1;
    int k = n-1;
    while(j<k){
        int y  = target - x - nums[j] - nums[k];
        if(y==0){
            return target;
        }else if(y>0){
            j++;
        }else {
            k--;
        }
        int temp = Math.abs(y);
        if(temp<min){
            min = temp;//取最小值
            ans = target - y;
        }

    }
}
return ans;

灵神的思路

灵神和我主体思路是相同的,区别在于他想到了很多的优化方案

对于这个算法,我们已经能够遍历出所有的情况,但是有些是没有必要的,可以直接排除,这个就是剪枝

优化1:去重
如果i>0,并且nums[i]==nums[i-1]代表这个数和前一个数相同,那么这个数就不用再次便利了
if (i > 0 && x == nums[i - 1]) {
    ontinue; // 优化1
}
优化2:排除极限情况
如果排序后的数组,最小的三个数和仍然大于target,就代表,后续的所有情况都会大于target,我们取最小,然后直接终止
int s = x + nums[i + 1] + nums[i + 2];
if (s > target) { // 后面无论怎么选,选出的三个数的和不会比 s 还小
	if (s - target < minDiff) {
	     ans = s; // 由于下面直接 break,这里无需更新 minDiff
	}
	break;
}
优化3: 排除极限情况
如果排序后的数组,当前数,加上后两个数仍然小于target,就代表后续的所有情况都会小于target,我们取最小,然后继续下一轮
s = x + nums[n - 2] + nums[n - 1];
if (s < target) { // x 加上后面任意两个数都不超过 s,所以下面的双指针就不需要跑了
    if (target - s < minDiff) {
        minDiff = target - s;
        ans = s;
    }
continue;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值