数组arr中任意2个数的和的绝对值最小值是多少?

博客解析了一道华为面试题,要求找到数组中任意两个数相加的绝对值最小值。解题思路包括使用排序和二分查找,先找到0的位置,然后遍历负数区,寻找每个负数对应的非负数区最接近的数,求和并取最小值。文章强调了二分查找在寻找最接近值中的应用,并提供了完整的Java实现代码。
摘要由CSDN通过智能技术生成

数组arr中任意2个数的和的绝对值最小值是多少?

提示:华为面试题原题


题目

数组arr,有正负,有0,无序的,请问你任意2个数的和,该和的绝对值最小值是多少?


一、审题

实例嘛,自然就是引导:
(1)-7 -3 -1 0 2 4 9
任选俩数,显然-1 和0 加起来绝对值是1应该是最小的
当然-3+4也是1
2-1=1也是1
-3+2=也是1


二、解题

我今天刚刚学的一个题,求子序列和的sum%m的最大值是多少?
差不多的思想:也是分开寻答案:
(1)答案可能来自所有的负数区【显然是最大的俩负数的和的绝对值】,比如-1-2绝对值为3
(2)答案可能来自所有的非负数区【显然是最小的俩整数的和的绝对值】,比如0+1=1
(3)答案可能同时来自负数区,可能来自非负数区,-1+0=1
因此呢,我们遇到一个负数x,需要找非负数区的最接近于|x|的的那个数
——敏感度来了,我之前做华为的笔试题,里面讲CPU的资源分配,也是将最接近于CPUcount的那台机器,这里就很重要了,这俩都是华为的题目,牛啊,都是靠二分查找的?
图1

先说本题:
需要找非负数区的最接近于|x|的的那个数 L–R范围内,找最接近于k的那个位置,使劲往左找,比如<=k的那个数位置是j,那j+1也可能是最接近k的,要比较一下,谁更接近。

找到最接近k的j位置的代码:

public static int mostApproach(int[] arr, int L, int R, int k){
        if (L > R) return -1;
        if (L == R) return arr[L];

        //R>L
        int j = L;
        while (L <= R){
            int mid = L + ((R - L) >> 1);
            if (arr[mid] <= k) {
                j = mid;//先记下它
                L = mid + 1;//继续往右找,看看能否找到==k的
            }else {
                //arr[mid] > k,过大,需要往左找
                R = mid - 1;
            }
        }
        //如果没有找到,说明全部都大于k呗,那最接近k的只能是L位置了
        if (j == R) return j;
        else return k - arr[j] <= k - arr[j + 1] ? j : j + 1;
        //返回的是最接近的,可能j+1会更接近哦
    }

然后算法大流程:
先排序,得到有序的arr,既然有0,则:
(1)先找到0那个位置,然后把俩负数拿过来,一个正数拿来,初始化一个max
(2)遍历所有的负数,找非负数区中最接近每一个负数的数,拿来求和,然后取max

public static int minAbsoluteValueOfTwoNum(int[] arr){
        if (arr == null || arr.length < 2) return 0;

        //先排序
        Arrays.sort(arr);//默认升序
        int N = arr.length;
        int min = 0;
        int j0 = mostApproach(arr, 0, N - 1, 0);//找到0处的位置
        //看看0左边有几个负数?
        if (j0 == 0) {
            min = Math.abs(arr[1]);//没有负数,只能是非负区的最小俩数
            return min;//没有负数,不说啥了,答案就是这个
        } else if (j0 == 1) min = Math.abs(arr[0]);//就一个负数,就一个最大负数+0
        else min = Math.abs(arr[j0 - 1] + arr[j0 - 2]);//超过2个负数,就最大俩负数先

        //然后遍历负数区,找0--N-1上最接近x的那个位置j
        for (int i = 0; i < j0; i++) {
            int j = mostApproach(arr, j0, N - 1, Math.abs(arr[i]));//k==arr[i]
            min = Math.min(min, Math.abs(arr[i] + arr[j]));
        }
        return min;
    }

测试:

public static void test(){
        int[] arr = {-7, -3, -1, 0, 2, 4,9};
        int[] arr3 = {-1, 0, 2, 4,9};
        int[] arr2 = {-7, -3, -1, 0, 1};
        System.out.println(minAbsoluteValueOfTwoNum(arr));
        System.out.println(minAbsoluteValueOfTwoNum(arr2));
        System.out.println(minAbsoluteValueOfTwoNum(arr3));
    }

    public static void main(String[] args) {
        test();
    }

总结

提示:重要经验:

1)二分查找,有序数组中小于等于k的最右的位置j,最接近k的位置j,这都是要熟悉的
2)华为那个最近进cpuCount的那个玩意,也要好好理解。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰露可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值