贪心 超级洗衣机

89 阅读1分钟

题目

有n个洗衣机,一共有m件衣服,每个洗衣机都放了任意数量衣服,每轮每个洗衣机可以向相邻洗衣机移动一个衣服,求最少多少轮可以使得所有洗衣机内的衣服数量一样

  • 对于 i 位置的洗衣机,假设 i 位置左边一共有 m 件衣服,l 台洗衣机,i 位置右边一共有 n 件衣服,r 台洗衣机,因为如果需要每台洗衣机衣服一致,所以总的衣服数量一定能够整除洗衣机数量,假设每台洗衣机平均分到 k 件衣服,如果整出左边理想衣服数量为lk,右边理想数量为yk
  • 如果 m-lk < 0 说明左边需要 |m-lk|数量衣服,m-lk>0,说明左边需要向右传递|m-lk|数量衣服,n-rk同理
  • 那么对于 i 位置就有三种情况
  • 如果 m-lk<0 && n-rk<0,说明左右两边都缺衣服,需要 i 位置向左和向右传递|m-lk|+|n-rk|衣服,因为每轮只能给一个,所以需要|m-lk|+|n-rk|轮
  • 如果 m-lk>0 && n-rk >0,说明左右两边都不缺衣服,都需要向 i 位置传递衣服,因为每轮只能给一个方向一个衣服,但接收方每轮可以接受2件衣服,所以 i 位置最多需要Math.max(||m-lk||,|n-rk|)轮就行了
  • 如果 其中一方>0,另一方<0,比如一方需要30件衣服,一方需要输出25件衣服,那么同样最多需要Math.max(||m-lk||,|n-rk|)轮就行了
  • 最后遍历每一个位置的洗衣机,求出每一个洗衣机需要的轮数,为了满足每个洗衣机条件,那么所有轮数中的最大值就是最后求得的移动最少的轮数,贪心策略:每一台机器都满足的情况下,取得的最小值
function process(arr) {
  const sum = arr.reduce((item, next) => item + next, 0);
  const len = arr.length;
  const avg = sum % len;
  if (avg !== 0) {
    return Infinity;
  }

  // i 位置之前的累加和,不包括i位置
  let leftSum = 0,
    min = 0;
  for (let i = 0; i < len; i++) {
    let leftRest = leftSum - i * avg; // i 位置左边实际需要的
    let rightRest = sum - leftSum - arr[i] - (size - i - 1) * avg; // i 位置右边实际需要的

    if (leftRest < 0 && rightRest < 0) {
      min = Math.max(min, Math.abs(leftRest) + Math.abs(rightRest));
    } else {
      min = Math.max(min, Math.max(Math.abs(leftRest), Math.abs(rightRest)));
    }

    leftSum += arr[i];
  }

  return min;
}