使数组的元素尽量平均的一道算法题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
woyixinyiyi
V2EX    程序员

使数组的元素尽量平均的一道算法题

  •  
  •   woyixinyiyi 2021-03-04 00:54:17 +08:00 2245 次点击
    这是一个创建于 1685 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想了半天没思路,请大佬赐教。

    题目给任意一个数组 eg:int[] array = {1, 2, 3, 9, 5};

    每次操作只能对某个数组下标对应的元素+1,另外的一个数组下标元素-1. 通过多次操作后,使各个元素的值尽量平均,(操作的次数尽量少,多也行,先实现功能再优化) 同时要求,输出每次移动的时候,是那个数组下标对应的元素加了还是减少了。

    eg:9 移动了三次到 1 输出三次 3->0 (9 的下标是 3,1 的下标是 0)

    9 移动了两次到 2 输出 2 此 3->1 
    12 条回复    2021-03-13 20:59:51 +08:00
    also24
        1
    also24  
       2021-03-04 01:09:54 +08:00 via Android
    先遍历一遍,求个平均值 A (也就是目标值)

    然后两个指针(下标)从头开始遍历,
    little 指针找 <=a-1 的数,找到就停下来;
    big 指针找 >= a+1 的数,找到就停下来;

    然后 big -> little 完成一次交换,输出一次;
    判断两个指针是否需要更新,继续输出一次。

    注意,考虑到不能整除的情况,可以维护一个 SUM,每次切换新指针的时候,将已经无法处理的数字减去,求剩余可操作数字的新的平均值。
    akira
        2
    akira  
       2021-03-04 03:00:33 +08:00
    没看懂。。你怎么移动,元素不还是那几个元素么,那不管你要什么结果,无非都是排序的事情吧
    kx5d62Jn1J9MjoXP
        3
    kx5d62Jn1J9MjoXP  
       2021-03-04 08:31:07 +08:00 via Android
    要考虑平均值不为整数的情况,会有一点细节,但是还是可以做到 O(n)
    woyixinyiyi
        4
    woyixinyiyi  
    OP
       2021-03-04 09:45:05 +08:00
    @also24
    我之前也是这样想的
    但是交换的时候 还有平均之外的值
    然后 big -> little 完成一次交换,输出一次;
    判断两个指针是否需要更新,继续输出一次。
    woyixinyiyi
        5
    woyixinyiyi  
    OP
       2021-03-04 09:45:37 +08:00
    @akira 排序数组下标不就变了么
    DeathBless
        6
    DeathBless  
       2021-03-04 09:45:52 +08:00
    先算平均值 并用坐标排序

    再用排序数组两头(一大 一小)的值做均衡

    任意一端的值达到平均值就把指针往中间挪一个?
    also24
        7
    also24  
       2021-03-04 10:13:09 +08:00 via Android
    @woyixinyiyi
    没看懂你的回复,什么叫做 『还有平均之外的值』
    siyemiaokube
        8
    siyemiaokube  
       2021-03-04 11:17:44 +08:00 via iPhone
    直接按照题意模拟就行了,开两个列表

    L1 储存大于 avg 的数,L2 储存小于 avg 的数字,先把 L1 尽可能地调整到 ceil(avg),L2 尽可能调整到 floor(avg)。

    然后 L1 与 L2 最多存在一者,其中还存在既不为 ceil(avg)也不为 floor(avg)的数字,把这个数字继续摊平就行了。
    siyemiaokube
        9
    siyemiaokube  
       2021-03-04 11:18:13 +08:00 via iPhone
    把这个数字继续摊平就行了-> 把这些数字继续摊平就行了
    bfdh
        10
    bfdh  
       2021-03-08 08:56:36 +08:00
    @also24 #7 应该说的是平均值不是整数的情况。如果平均值不是整数,应该要四舍五入之后做为目标值。
    also24
        11
    also24  
       2021-03-12 12:26:32 +08:00
    @bfdh #10
    不能直接四舍五入,直接四舍五入存在不均匀的情况。

    例如 4 4 4 3 7 这一组数字,平均值 4.4,四舍五入以后变成了 4,会导致处理到 3 的时候,误认为只需要增加到 4 就够了,实际上这个数列的最佳结果是 4 4 4 5 5 才对。


    所以我在 1 楼的回答里,提到了平均值需要在每一次切换指针的时候进行更新:



    这样,当指针移到最后两个位置的时候,平均值已经更新为 5 了,就能正确处理最后两个数字。
    woyixinyiyi
        12
    woyixinyiyi  
    OP
       2021-03-13 20:59:51 +08:00
    @also24
    谢谢老哥
    实现了一版

    public class 端盘子移动问题 {
    /**
    * 思路
    * 1.计算出 平均值,四舍五入。这样会尽量的平均
    * 2.维护两个指针,分别记录小于平均值的指针,和大于平均值的指针
    * 3.然后移动大小指针来均值计算。
    */
    public static void main(String[] args) {
    int[] array = {1, 2, 3, 4, 5};

    double sum = 0;
    for (int i = 0; i < array.length; i++) {
    sum += array[i];
    }

    int avg = new BigDecimal(sum / array.length).setScale(0, BigDecimal.ROUND_HALF_UP).toBigInteger().intValue();

    int small = 0;
    int big = 0;

    while (small < array.length && big < array.length) {


    while (small < array.length && array[small] > avg) {
    small++;
    }

    while (big < array.length && array[big] < avg) {
    big++;
    }

    if (big >= array.length || small >= array.length) break;

    //说明小于平均值的缺的盘子更多
    if (Math.abs(array[small] - avg) > Math.abs(array[big] - avg)) {
    int cha = Math.abs(array[big] - avg);
    array[big] -= cha;
    array[small] += cha;
    big++;

    } else {
    int cha = Math.abs(array[small] - avg);
    array[small] += cha;
    array[big] -= cha;
    small++;

    }
    }
    }

    }
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1332 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 17:10 PVG 01:10 LAX 10:10 JFK 13:10
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86