• 最接近的三数之和


    题意

    给你一个长度为 n 的整数数组 nums 和一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

    返回这三个数的和。假定每组输入只存在恰好一个解。

    难度

    中等

    示例

    输入:nums = [-1,2,1,-4], target = 1

    输出:2

    解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

    输入:nums = [0,0,0], target = 1

    输出:0

    分析

    既然是最接近的三数之和,那显然我们就可以采用三数之和的解思路,先排序,然后固定一个数,再用双指针去找另外两个数。

    三数之和的时候和为 0,这里的和为最接近 target 的一个数,那其实解法就真的差不多了。

    1. class Solution {
    2. public int threeSumClosest(int[] nums, int target) {
    3. // 对数组进行排序
    4. Arrays.sort(nums);
    5. // 数组长度
    6. int n = nums.length;
    7. // 初始化最接近的和为前三个元素的和
    8. int closestSum = nums[0] + nums[1] + nums[2];
    9. // 遍历数组,除了最后两个元素(因为我们需要三个数)
    10. for (int i = 0; i < n - 2; i++) {
    11. // 双指针初始化,left 指向当前元素之后的元素,right 指向数组最后一个元素
    12. int left = i + 1, right = n - 1;
    13. while (left < right) {
    14. // 计算当前三个数的和
    15. int sum = nums[i] + nums[left] + nums[right];
    16. // 如果当前和与目标值的差的绝对值小于最接近和与目标值的差的绝对值
    17. if (Math.abs(target - sum) < Math.abs(target - closestSum)) {
    18. // 更新最接近的和
    19. closestSum = sum;
    20. }
    21. // 根据和与目标值的比较,移动指针
    22. if (sum > target) {
    23. right--; // 和大于目标值,移动右指针向左
    24. } else if (sum < target) {
    25. left++; // 和小于目标值,移动左指针向右
    26. } else {
    27. return sum; // 如果和等于目标值,直接返回当前和
    28. }
    29. }
    30. }
    31. // 返回找到的最接近的和
    32. return closestSum;
    33. }
    34. }

    我们来简单分析下:

    ①、排序:首先对数组进行排序。双指针的前提就是数组要有序,这样才方便移动指针。

    ②、初始化最接近 target 的和:假设数组中前三个数的和就是最进阶 target 的值。

    ③、遍历数组:遍历数组,固定一个数 nums[i]。

    1. 双指针查找:在 nums[i] 后面的数组部分设置双指针,一个是 i 的下一位 i + 1,另一个是数组的末尾 n - 1。
    2. 移动这两个指针,寻找和最接近 target 的三数组合。
    3. 更新最接近的和:如果找到更接近 target 的和,就更新这个最接近的和。比如说,初始的和为 10,target 为 2,那如果我们找到了一个和为 5 的三数组合,那这个和就比 10 更接近 2,所以我们就更新这个最接近的和为 5。

    ④、终止条件:如果某次三数之和等于 target,直接返回 target,因为不能更接近了。

    这里需要注意的两个点,一个是如何判断最接近的和,我们用了 Math.abs() 方法,这个方法是取绝对值的意思,比如说 Math.abs(-1) 的结果就是 1,Math.abs(1) 的结果还是 1。

    当一个数与目标数 target 的差越小,那么这个数也就越接近 target。相信大家都能理解,5-3=2 < 10-3=7,那么 5 就比 10 更接近 3。

    1. if (Math.abs(target - sum) < Math.abs(target - closestSum)) {
    2. // 更新最接近的和
    3. closestSum = sum;
    4. }

    另外一个点是移动左指针还是右指针,当 sum 大于 target,说明 sum 太大了,需要减小 sum,那么就移动右指针,反之,如果 sum 小于 target,说明 sum 太小了,需要增大 sum,那么就移动左指针。

    1. if (sum > target) {
    2. right--; // 和大于目标值,移动右指针向左
    3. } else if (sum < target) {
    4. left++; // 和小于目标值,移动左指针向右
    5. } else {
    6. return sum; // 如果和等于目标值,直接返回当前和
    7. }

    当输入是 nums = [-1,2,1,-4], target = 1 的时候,就需要移动左指针,因为 sum 太小了,需要增大 sum。

    好,来看一下题解效率,还不错。

    总结

    那刷题其实就是这样,学会举一反三,遇到不同的题型,尽量去找到和它相似的题型,能不能按照之前的解题思路快速把这道题解出来,解出来后再想办法去优化。

  • 相关阅读:
    Fast-ParC学习笔记
    公司员工培训管理系统的开发研究(J2EE)
    【2023集创赛】安谋科技杯二等奖作品: 智能体感游戏机
    Nmap 诸神之眼深度解析
    携创教育:广东省成人高考录取分数线是多少?通过率高吗?
    如何更改表单必填红星的位置
    【数据结构】—— Trie/并查集/堆
    关于不完全类型的认识
    「MySQL高级篇」MySQL日志、事务原理 -- undolog、redolog、binlog、两阶段提交
    服务网格和CI/CD集成:讨论服务网格在持续集成和持续交付中的应用。
  • 原文地址:https://blog.csdn.net/qq_64948664/article/details/137208582