LeetCode打卡 16. 最接近的三数之和(双指针详解)

8 篇文章 0 订阅
5 篇文章 0 订阅

16. 最接近的三数之和

难度:中等

给定一个包括 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


class Solution {
    public int threeSumClosest(int[] nums, int target) {
    }
}

解题思路:

  • 双指针法
  • 先让数组有序,也就是需要先对数组进行排序
  • 然后每次固定一个元素,再去寻找另外两个元素,也就是双指针

我们在声明变量三数之和sum时,可以直接以nums[0] +nums[1]+nums[2]的和赋值,绝对不能赋值为0因为这个sum必须是数组中某3个元素的和。


接下来先对原数组进行排序
Arrays.sort(nums);
java中底层这里用的快排 意思就是说 最好时间复杂度为O(nlgn)最坏为O(n^2)


对于已经排好序的数组我们开始遍历
这里可以先进行一次去重,也就是
if (i!=0&&nums[i]==nums[i-1]) continue;

如果在下标不为0的情况下,如果当前值和上一个值相等就跳到下一次循环(已经计算完当前值和位置的所有情况)


然后我们可以定义两个指针 分别指向当前元素的下一个元素和数组最后一个元素,这个时候我们可以保证nums[i]+nums[j]+nums[k]是最大的(数组有序)
于是int mid = nums[i]+nums[j]+nums[k];
当mid与target的距离小于sum与target的距离时就更新sum
判断当sum==target的时候直接return sum; 题目只要求一个结果。


然后可以比较mid 和 target 的值
如果mid > target 说明减少mid才能靠近target
此时应该k-1
(为了避免出现重复的步骤,比如中间是111222的情况,我们可以进行二次去重)
(也就是k-1还是大鱼j并且下标k+1元素值和k元素相等说明重复了,直接k-1一次)
如果mid < target 说明增加mid才能靠近target
此时应该j+1
(也就是j+1还是小鱼k并且下标j-1元素值和j元素相等说明重复了,直接j+1一次)

实际代码如下:
顺带整个遍历数组的同时遍历了当前元素后的元素,时间复杂度为O(N2)和快排相加还是O(N2) 空间复杂度应为O(logN) (快排空间)

package com.czh.factory;
import org.junit.Test;
import java.util.Arrays;
/**
 * @author zhCoding
 * @Description:
 * @create 23:57
 */
public class AlmostThree {
    @Test
    public void test1(){
        int[] arr = new int[]{87,6,-100,-19,10,-8,-58,56,14,-1,-42,-45,-17,10,20,-4,13,-17,0,11,-44,65,74,-48,30,-91,13,-53,76,-69,-19,-69,16,78,-56,27,41,67,-79,-2,30,-13,-60,39,95,64,-12,45,-52,45,-44,73,97,100,-19,-16,-26,58,-61,53,70,1,-83,11,-35,-7,61,30,17,98,29,52,75,-73,-73,-23,-75,91,3,-57,91,50,42,74,-7,62,17,-91,55,94,-21,-36,73,19,-61,-82,73,1,-10,-40,11,54,-81,20,40,-29,96,89,57,10,-16,-34,-56,69,76,49,76,82,80,58,-47,12,17,77,-75,-24,11,-45,60,65,55,-89,49,-19,4};
        System.out.println(threeSumClosest(arr, -275));
    }
    public int threeSumClosest(int[] nums, int target) {
        if (nums==null||nums.length<3) throw new RuntimeException("输入数组有误!");
        int sum = nums[0] +nums[1]+nums[2];
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if (i!=0&&nums[i]==nums[i-1]) continue;
            int j=i+1,k=nums.length-1;
            while (j<k){
                int mid = nums[i]+nums[j]+nums[k];
                if (Math.abs(sum-target)>Math.abs(mid-target)){
                    sum = mid;
                }
                if (mid==target) return target;
                if (mid > target){
                    k--;
                    while ((j+1<k && nums[k+1]==nums[k]))
                        k--;
                }
                if (mid < target){
                    j++;
                    while ((j+1<k && nums[j-1]==nums[j]))
                        j++;
                }
            }
        }
        return sum;
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值