zoukankan      html  css  js  c++  java
  • 【力扣算法】数组(3):最接近的三数之和

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

    例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.

    与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

    原题链接:https://leetcode-cn.com/problems/3sum-closest


    题目分析

    一开始我顺着数组(2)的思路,很容易认为是不断地找加和结果和目标值相近的组合。如$1$的话,先找加和值为$1$,然后是$0$和$-1$。这样的话,可能就是数组(2)的基础上,删除去重的代码,然后遍历一下目标值即可。但换一个思路想想,题目只要求输出一个“最接近”的数,应该是找最小,所以直接比大小就可以了。公式为

    $$diff = min { diff,abs({ m{target - }}sum)} $$

    解法一:暴力求解

    目前遇到的数组题似乎都可以用暴力求解解决。原因可能是数组给定后,边界值明确,暴力求解到底还是一定的值域内进行?

    暴力求解的思路就是三层循环,从内到外遍历所有组合情况,每次对组合加和值与目标值得关系进行判断。然后输出最终的比较结果即可。代码如下:

     1 static int threeSumClosest(int[]nums, int target) {
     2     if(nums.length<3 || nums == null)
     3         return 0;
     4     
     5     int n = nums.length;
     6     int diff = 100000000, sum = 0, minsum = 10000000;
     7     for(int i=0;i<n-2;i++) {//left space for pre and post
     8         for(int j=i+1;j<n-1;j++) {
     9             for(int k=j+1;k<n;k++) {
    10                 sum = nums[i]+nums[j]+nums[k];
    11                 if(diff>Math.abs(target-sum)) {
    12                     diff = Math.abs(target-sum);
    13                     minsum = sum;
    14                 }                
    15             }        
    16         }        
    17     }
    18     return minsum;    
    19 }

    这次有意识地判断了不定式写入的位置(第10行)。

    解法二:双指针

    双指针的题目做过也不止一题了,是一种用空间复杂度换时间复杂度的方法。

    但是和数组(2)的情况一样,都需要进行排序,使得能够遍历完所有的条件(我开始忘记排序,发现会遗漏情况)。

    双指针是在三数中先固定最小数(最大数也是一样的),然后在剩下的数值区间内遍历。设三数和为$sum = nums[achor] + nums[pre] + nums[post]$,迭代条件是

    $left{egin{array}{l}{ ext { sum }< ext {target, pret }++} \ { ext { sum }> ext {target, post}--} \ { ext { sum }= ext {target, return}}end{array} ight.$

    之后再继续内循环。

    代码为

    if(sum<target) pre++;
    else if (sum>target) post--;
    else if (sum==target) return minsum;

    显然,若不排序,双指针迭代就没有意义(考虑到是有序数列(左往右递增),当然$sum$小于$target$时,将左指针右移,总和会变大)。

    分析内循环的循环条件为$pre<post$,外循环的循环条件是$achor<=length-2$,这里考虑一下指针迭代会不会越界:

    以左指针为例,内循环的边界条件是$pre=post-1$,此时若达成条件$pre++$,那么再进行内循环时,便满足终止条件、内循环结束,故不会数组越界。右指针迭代同理。

    整体代码为:

     1 static int threeSumClosest(int[] nums, int target) {
     2     if(nums.length<3 || nums == null)
     3         return 0;
     4     
     5     int n = nums.length;
     6     int achor = 0, pre = achor + 1, post = n - 1;
     7     int diff = 100000000, sum = 0, minsum = 10000000;
     8     
     9     Arrays.sort(nums);
    10     
    11     while(achor<=n-2) {//left space for the noodles of pre and post
    12         while(pre<post) {
    13             sum = nums[achor]+nums[pre]+nums[post];
    14             if(diff>Math.abs(target-sum)) {
    15                 diff = Math.abs(target-sum);
    16                 minsum = sum;
    17             }
    18             if(sum<target) pre++;
    19             else if (sum>target) post--;
    20             else if (sum==target) return minsum;                
    21         }
    22         achor++;pre=achor+1;post=n-1;
    23     }
    24     return minsum;
    25 }

    这里要说明的是,第14行到第17行的代码,一开始是这么写的:

    diff=Math.min(diff, Math.abs(target-sum));

    单这行代码的作用而言,是没错的。让我觉得棘手的是最后返回值第24行,我就无法输出最小的和了。我曾想过做$diff$和$target$之间的运算,但是后来想到(实际上程序提交后不符合...)这样的运算结果应该有两个。所以只能作罢、用一个变量来承接最小的和。

    还有一个事情,在第18行到第20行,我曾作死的把判断条件改成了$diff$的正负值比较。问题是$diff$永远都是非负数。所以是自己考虑不周了。


     总结

    这道题还算是简单。

    • 只要一开始审题要明确(这里其实是比较大小,而不是查找)。
    • 然后是搞清楚边界条件、适当推理一下
    • 最后还是要搞清楚输出的是什么,我觉得一开始在变量声明时就可以注意了
  • 相关阅读:
    MySQL-keepalived做高可用
    Linux-服务管理
    MySQL-CentOS7上安装Mysql5.7
    MySQL-查看DB文件位置
    游戏编程与游戏种类
    计算机
    python
    python中的构造函数
    IndentationError:expected an indented block错误解决
    python程序的pdb调试方法
  • 原文地址:https://www.cnblogs.com/RicardoIsLearning/p/12034034.html
Copyright © 2011-2022 走看看