• 超级洗衣机问题


    作者:Grey

    原文地址:超级洗衣机问题

    题目链接:LeetCode 517. 超级洗衣机问题

    主要思路

    有两个显而易见的结论:

    假设所有衣服的数量之和是sum,如果sum % N != 0,则无论如何都无法做到让所有洗衣机平分衣服。

    假设洗衣机的数量是size,那么每个洗衣机需要分担avg = sum / size这么多件衣服。

    假设我们在i位置,i左侧有i-1个位置,这i个位置上应该要有i*avg件衣服,假设现在i位置之前的累加和是leftSum, 用

    leftRest = leftSum - i * avg
    

    得到的结果就是i左侧还差多少件衣服(如果是负数,就是富余多少件衣服)。

    同理,i右侧有size - i - 1个位置,这size - i - 1 个位置理论上应该有avg * (size - i - 1)件衣服。用

    rightRest = sum - leftSum - avg*(size - i - 1)
    

    得到的结果就是i右侧还差多少件衣服(如果是负数,就是富余多少件衣服)。

    如果

    leftRest < 0 && rightRest < 0
    

    说明i位置两侧都不够衣服,要让i位置同时给左侧和右侧都贡献衣服,因为可以不可同时贡献,所以i贡献的衣服是

    Math.abs(leftRest) + Math.abs(rightRest)
    

    举例说明:

    [3,6,3]这个数组,对于中间位置的6来说,要向左侧贡献1件衣服,要向右侧贡献1件衣服。

    除了这种情况,要么左侧衣服多了,要不右侧衣服多了,要不两侧衣服都多了,这个时候,需要两侧向i位置贡献一部分衣服,因为左右两侧可以同时向i位置贡献,所以贡献的衣服数量取决于是两侧多的数量,即:

    Math.max(Math.abs(leftRest),Math.abs(rightRest))
    

    举例说明:

    [5,1,6]这个数组,对于中间位置的1来说,左侧需要给它贡献1件衣服,右侧需要给它贡献2件衣服,而且根据题目条件,这种情况是可以同时贡献衣服的,所以只需要两轮即可。

    自此,所有情况讨论完毕,完整代码如下:

    public static int findMinMoves(int[] arr) {
            if (null == arr || 0 == arr.length) {
                return 0;
            }
            int sum = 0;
            int size = arr.length;
            for (int item : arr) {
                sum += item;
            }
            if (sum % size != 0) {
                return -1;
            }
            int avg = sum / size;
            int leftSum = 0;
            int ans = 0;
            for (int i = 0; i < size; i++) {
                // 左侧还差多少
                int leftRest = leftSum - i * avg;
                // 右侧还差多少
                int rightRest = (sum - leftSum - arr[i]) - (size - i - 1) * avg;
                if (leftRest < 0 && rightRest < 0) {
                    // 左侧右侧都差一些才到平均值
                    // 此时就需要中间位置向左边和右边都丢一些衣服
                    ans = Math.max(ans, Math.abs(leftRest) + Math.abs(rightRest));
                } else {
                    // 左侧多,右侧少,多的通过中间丢一些到左侧
                    // 右侧少,左侧多,多的通过中间丢一些到右侧
                    // 左右侧都多,则可以**同时**向中间丢衣服
                    ans = Math.max(ans, Math.max(Math.abs(leftRest), Math.abs(rightRest)));
                }
                leftSum += arr[i];
            }
            return ans;
        }
    

    更多

    算法和数据结构笔记

  • 相关阅读:
    HDU-1561
    POJ 1088
    UESTC-878
    CodeForces
    HDU 5753
    HDU 1568
    二分图入门题
    二分图匹配入门题
    树形dp入门
    UVA
  • 原文地址:https://www.cnblogs.com/greyzeng/p/16335452.html
Copyright © 2020-2023  润新知