【问题标题】:Minimum transfer to make array equal使数组相等的最小转移
【发布时间】:2021-12-28 04:35:27
【问题描述】:

面试时会问这个问题。我仍然无法找到尝试这个问题的正确方法。

给定一个数组 = [7,2,2] 找到使数组元素几乎相等所需的最小传输次数。如果这不可能,则较大的元素应位于左侧。

在上面的例子中,数组的最终状态是 [4,4,3],答案是 2+ 1 =3。 我们将 2 从 7 转移到前 2,然后我们将另一个 1 从 7 转移到 2。

如果输入是 [2,2,7],那么答案将是 4,因为我们需要在左侧保留更大的元素。 最终状态 = [4,4,3] 2 从 7 转移到两个 2 使最终计数为 4。

【问题讨论】:

  • 期望是什么?最终计数或最终状态或两者兼而有之?
  • 最终计数是想要的答案
  • 计算最终状态,然后对所有需要增加的数字求和。
  • 如何计算最终状态..?
  • @GJoshi 检查我的答案。您会惊讶地发现解决方案如此简单。

标签: algorithm data-structures


【解决方案1】:

一次完成 1 个单位的最小传输量是输入与所需数组不同的总数量的一半。根据您给出的内容,“几乎相等”似乎并不意味着任何复杂性。

【讨论】:

    【解决方案2】:

    解决方案是想象目标数组将是什么。这个目标数组将仅取决于原始数组中的值的总和,以及数组的长度(显然必须保持不变)。

    如果值的总和是数组长度的倍数,则目标数组中的所有值都将相同。但是,如果有余数,则该余数表示数组值的数量,该数量将比数组末尾的某些值多一。

    我们实际上不必存储那个目标数组。它由和除以数组长度的商和余数隐式定义。

    函数的输出是实际输入数组值与任意数组索引处的预期值的差值之和。我们应该只计算正的差异(即从一个值中转移),否则我们将计算两次转移——一次在传出端,一次在传入端。

    这是一个基本 JavaScript 的实现:

    function solve(arr) {
        // Sum all array values
        let sum = 0;
        for (let i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
    
        // Get the integer quotient and remainder
        let quotient = Math.floor(sum / arr.length);
        let remainder = sum % arr.length;
    
        // Determine the target value until the remainder is completely consumed:        
        let expected = quotient + 1;
    
        // Collect all the positive differences with the expected value
        let result = 0;
        for (let i = 0; i < arr.length; i++) {
           // If we have consumed the remainder, reduce the expected value
           if (i == remainder) {
               expected = quotient;
           }
           let transfer = arr[i] - expected;
           // Only account for positive transfers to avoid double counting
           if (transfer > 0) {
               result += transfer;
           }
        }
        
        return result;
    }
    
    let array = [7,2,2];
    console.log(solve(array)); // 6

    【讨论】:

      【解决方案3】:

      让我们开始表单目标数组。这是什么?

      拥有{7, 2, 2},我们想获得{4, 4, 3}。所以每个项目至少是3,一些顶级项目是3 + 1 == 4。 算法是

      let sum = sum(original)
      let rem = sum(original) % length(original)  # here % stands for remainder
      
      target[i] = sum / length(original) + (i < rem ? 1 : 0) 
      

      拥有originaltarget

      original: 7 2 2
      target:   4 4 3
      transfer: 3 2 1 (6 in total)
      

      注意,那个

      1. transfer[i] 只是一个绝对的区别:abs(original[i] - target[i])
      2. 我们对每个 transfer 计数 两次:一次我们减去,然后我们 添加

      所以答案是

      sum(transfer[i]) / 2 == sum(abs(original[i] - target[i])) / 2 
      

      代码(c#)

      private static int Solve(int[] initial) {
        // Don't forget about degenerated cases
        if (initial is null || initial.Length <= 0)
          return 0;  
      
        int sum = initial.Sum();
        int rem = sum % initial.Length;
      
        int result = 0;
      
        for (int i = 0; i < initial.Length; ++i) 
          result += Math.Abs(sum / initial.Length + ((i < rem) ? 1 : 0) - initial[i]);
        
        return result / 2;  
      }
      

      演示: (Fiddle)

          int[][] tests = new int[][] {
              new int[] {7, 2, 2},
              new int[] {2, 2, 7},
              new int[] {},
              new int[] {2, 2, 2},
              new int[] {1, 2, 3},
          };
          
          string report = string.Join(Environment.NewLine, tests
            .Select(test => $"[{string.Join(", ", test)}] => {Solve(test)}"));
          
          Console.Write(report);
      

      结果:

      [7, 2, 2] => 3
      [2, 2, 7] => 4
      [] => 0
      [2, 2, 2] => 0
      [1, 2, 3] => 1
      

      【讨论】:

        【解决方案4】:

        在我看来,这是一个可以通过greedy 方法解决的简单问题。

        步骤:

        1. 总结input数组元素S,除以它的长度n。可以说,商是Q,余数(mod)是R。然后,最终数组target 将具有1st R elements with value = Q+1。其余元素将是 Q
        2. 传输次数将是input and target 数组中每个(对应)位置的绝对差之和的一半。

        示例:

        Input [7, 2, 2]
        S=11 n=3 Q=11/3=3 R=11%3=2
        Target [3+1, 3+1, 3]
        Answer = (abs(7-4) + abs(2-4) + abs(2-3)) / 2 = 3
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-02-27
          • 2022-10-23
          • 2021-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多