Leetcode刷题(二十)

文章讲述了如何在给定整数数组中找到三个数,使得它们的和与目标值最接近,通过先排序数组并使用双指针法,优化了时间复杂度至O(n^2)。作者提供了两种代码实现并讨论了优化策略,如去重和边界判断。
摘要由CSDN通过智能技术生成

最接近的三数之和(Medium)

给你一个长度为 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
-104 <= target <= 104
Related Topics
数组
双指针
排序

思路分析

这道题最简单粗暴的方法就是遍历数组中所有三个数的组合,这种遍历方式固定的方法就是使用三层循环,时间复杂度也就是O(n^3)。但是这道题要求三个数的和最小,那么就可以进行优化,不使用三层循环,而是在将数组变成有序数组之后,在第二层使用双指针的方法。这样就只用使用两层循环,将时间复杂度降低为 O(n^2)。

我们设置一些变量,minMod:三数和到target的距离、difference:三数和与target的差。在这里我们考虑几种情况,第一种:minMod等于0,说明满足条件直接输出结果。第二种:minMod不等于0,说明还要完成遍历查看是否有更加符合条件的三数和,第二种情况又分为两种,一种是difference大于零,这种说明需要增加三数和的大小,所以将左指针右移增大三数和,同时判断与target的距离是否变小。另一种是difference小于零,这种情况同理。这样第二层只需完成一次循环就可以得到结果。

代码实现

import java.util.Arrays;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int minMod = Integer.MAX_VALUE;
        int difference = 0;
        int result = nums[0] + nums[1] + nums[nums.length-1];
        for (int i = 0; i < nums.length - 2; i++ ){
            int left = i + 1;
            int right = nums.length - 1;
            while (left < right){
                int result_temp = nums[i] + nums[right] + nums[left];
                difference = target - result_temp;
                if (difference == 0) return nums[i] + nums[right] + nums[left];
                if (difference > 0){
                    if (Math.abs(difference) <= minMod){
                        minMod = Math.abs(difference);
                        result = result_temp;
                    }
                    left++;
                }else if (difference < 0){
                    if (Math.abs(difference) <= minMod){
                        minMod = Math.abs(difference);
                        result = result_temp;
                    }
                    right--;
                }
            }

        }

        return result;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

在这里插入图片描述

代码优化

1.元素重复:在排序之后,重复的数字会排列在一起,重复遍历这些数字是没有意义的,所以可以添加去重的操作。
在这里插入图片描述
在这里插入图片描述
2.target与每层遍历结果的界限问题:由于数组是有序的,所以每次遍历的left与right之间肯定存在着最值,nums[left] + nums[left+1]是最小值,nums[right] + nums[right-1]是最大值,如果target小于或大于这两个值,就没有必要继续循环,所以加上一个判断就可以减少循环的次数。
在这里插入图片描述
在这里插入图片描述

最后代码

import java.util.Arrays;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int minMod = Integer.MAX_VALUE;
        int difference = 0;
        int result = nums[0] + nums[1] + nums[nums.length-1];
        for (int i = 0; i < nums.length - 2; i++ ){
            int left = i + 1;
            int right = nums.length - 1;
            while (left < right){
                int min = nums[i] + nums[left] + nums[left + 1];
                if(target < min){
                    if(Math.abs(result - target) > Math.abs(min - target))
                        result = min;
                    break;
                }
                int max = nums[i] + nums[right] + nums[right - 1];
                if(target > max){
                    if(Math.abs(result - target) > Math.abs(max - target))
                        result = max;
                    break;
                }
                int result_temp = nums[i] + nums[right] + nums[left];
                difference = target - result_temp;
                if (difference == 0) return nums[i] + nums[right] + nums[left];
                if (difference > 0){
                    if (Math.abs(difference) <= minMod){
                        minMod = Math.abs(difference);
                        result = result_temp;
                    }
                    left++;
                }else if (difference < 0){
                    if (Math.abs(difference) <= minMod){
                        minMod = Math.abs(difference);
                        result = result_temp;
                    }
                    right--;
                }
            }
            while(i<nums.length-2 && nums[i] == nums[i+1]) i++;

        }

        return result;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值