LeetCode0016-最接近的三数之和

本文详细介绍了LeetCode第0016题的解决方案,通过双指针法寻找数组中三个整数,使它们的和与目标值最接近。文章包含解题思路、代码实现及优化措施。
摘要由CSDN通过智能技术生成

LeetCode0016-最接近的三数之和

题目:

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

提示:

  • 3 <= nums.length <= 10^3
  • -10^3 <= nums[i] <= 10^3
  • -10^4 <= target <= 10^4

分析:

解题思路
双指针法:

  • 先让数组有序,也就是需要对数组进行排序
  • 然后每次固定一个元素,再去寻找另外俩个元素,也就是双指针
双指针法的代码实现(代码:Solution01)
  • 利用 Arrays.sort(nums) 对数组进行排序。
  • 初始化一个用于保存结果的值 result = nusm[0] + nums[1] + nums[2] (不要自己设初值,直接从数组中抽取三个元素,假设这是最接近的三数之和,然后再更新就是了)。
  • 利用下标 i 对数组进行遍历,此时就是在固定第一个元素,注意,下标 i 的边界为 i < nums.length-2,否则设置指针的时候会出现数组越界。
  • 每次遍历的过程中设置两个指针,分别是 left = i + 1、right = nums.length - 1。
  • 检查 sum = nums[i] + nums[left] + nums[right]与 target 的距离,如果该距离比之前保存的 result 与 target 的距离更小,就更新 result。
  • 然后就是移动双指针。
  • 如果 sum 的值比 target 大,那么我们让 right–,因为数组是有序的,right --会使得下一次的 sum 更小,也就更接近 target 的值
  • 同理,如果 sum 的值比target 小,那么我们让 left++。·
  • left++ 和 right-- 的界限自然是 left != right,如果 left == right,说明我们已经将所有的元素都遍历过一遍了。
    重复上面的操作,直到i循环结束为止,返回 result。
双指针法的优化

解决元素重复问题(代码:Solution02)

  • 举个例子,nums = [1,1,1,2,3] target = 7,那么最终的结果应该是 6 (1 + 2 + 3)。
  • 但是按照上面的代码,在遍历的时候 nums[i]会重复的等于 1 这个数,但是其实之前 nums[i] 等于 1 已经遍历过了,后面的遍历都属于无用的遍历。
  • 所以可以添加去重的操作

解决超越界限的问题(代码:Solution03)

  • 举个例子,nums = [-3,-1,3,4,5]。
  • 假设 i = 0,left = 1,right = 4,那么每次 left 和 right 之间都有许多元素,那么 left 和 right 之间的元素之和肯定也有一个最小值和一个最大值。
  • 就如同 left = 1,right = 4,那么移动指针的情况下,nums[left] + nums[right] 的最小值肯定为 nums[left] + nums[left + 1],因为这两个元素是 left 和 right 范围内能取到的最小的两个元素,同理可证最大值。
  • 如果 target 的值比 nums[i] + nums[left] + nums[left + 1] 的值还小,那么双指针无论怎么取,最后都会取到 nums[i] + nums[left] + nums[left + 1]。
  • 同理可证 target 的值比nums[i] + nums[right] + nums[right - 1] 的值还大的情况。
  • 所以可以增加一个判断,满足条件的情况下就可以直接取值,而不需要双指针一步步的判断来进行取值,减少了双指针的移动。

解决三数之和等于target的问题(代码:Solution04)

  • 举个例子,nums = [1,1,2,3,4,5,6,10] target = 12,那么最终的结果应该是 12 (1 + 1 + 10)。
  • 有些时候,可能会直接找到三数之和等于 target 的情况,此时直接返回结果即可,不需要在进行之后的循环,因为不可能有数比他自己更接近自己了。
代码:
import java.util.Arrays;

/**
 * 0016-最近的三数之和
 * 给定一个包括n个整数的数组nums和一个目标值 target 。找出nums中的三个整数,使得
 * 它们的和与target最接近。返回这三个数的和。假定每组输入只存在唯一答案
 * <p>
 * 示例:
 * <p>
 * 输入:nums = [-1,2,1,-4], target = 1
 * 输出:2
 * 解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
 * <p>
 * 提示:
 * <p>
 * 3 <= nums.length <= 10^3
 * -10^3 <= nums[i] <= 10^3
 * -10^4 <= target <= 10^4
 */

/**
 * 双指针法
 */
class Solution01 {
   
    public int threeSumClosest(int[] nums, int target) {
   
        // 对数组元素进行排序
        Arrays.sort(nums);
        // 初始化用于保存结果的值
        int result = nums[0] + nums[1] + nums[2];
        // 利用下标i对数组进行遍历
        for (int i = 0; i < nums.length - 2; i++) {
   
            // 每次遍历过程中,设置俩个指针
            int left = i + 1;
            int right = nums.length - 1;
            // 俩个指针相遇,则循环结束
            while (left != right) {
   
                // 计算三个数之和
                int sum = nums[i] + nums[left] + nums[right];
                // 当前状态与target距离小于已经保存的最优状态,则更新result
                if (Math.abs(sum - target) < Math.abs(result - target)) 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值