题目描述
假设有 n
台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。
在 每一步操作 中,你可以选择 任意 m
(1 <= m <= n
) 台洗衣机,与此同时 将每台洗衣机的 一件衣服 送到相邻的一台洗衣机。
给定一个非负整数数组代表从左至右每台洗衣机中的衣物数量,请给出能让所有洗衣机中剩下的衣物的数量相等的 最少的操作步数。如果不能使每台洗衣机中衣物的数量相等,则返回 -1
。
样例
输入:machines = [1,0,5]
输出:3
解释:
第一步: 1 0 <-- 5 => 1 1 4
第二步: 1 <-- 1 <-- 4 => 2 1 3
第三步: 2 1 <-- 3 => 2 2 2
输入:machines = [0,3,0]
输出:2
解释:
第一步: 0 <-- 3 0 => 1 2 0
第二步: 1 2 --> 0 => 1 1 1
输入:machines = [0,2,0]
输出:-1
解释:
不可能让所有三个洗衣机同时剩下相同数量的衣物。
注意
n == machines.length
1 <= n <= 10^4
0 <= machines[i] <= 10^5
算法
(线性遍历,答案分解) $O(n)$
- 由于每次操作每台洗衣机只能选择向左或者向右运送一件衣服,且多个洗衣机可以并行同时运送,故必定存在一个洗衣机,它运送的衣服数量等于答案。
- 我们可以枚举每一台洗衣机,计算经过它运送的衣服的数量。
- 首先如果衣服的总数量是洗衣机的整数倍,则必定存在一个解;否则返回
-1
。 - 然后逐一枚举洗衣机,假设当前枚举的洗衣机编号为
i
,则统计left_sum = [0, i - 1]
中衣服的总数量与right_sum = [i + 1, n - 1]
中衣服的总数量,若发现left_sum < i * avg
,即i
左边的衣服数量少,故需要经过这台洗衣机从右向左运送的衣服数量为r_2_l = i * avg - left_sum
。从左向右运行的衣服数量l_2_r
同理。 r_2_l + l_2_r
求和就是这台洗衣机的工作量,对每一台洗衣机都这样求和得到工作量,取工作量最大的洗衣机就是答案。
时间复杂度
left_sum
和right_sum
可以实时维护,每个洗衣机仅遍历一次,故时间复杂度为 $O(n)$。
C++ 代码
class Solution {
public:
int findMinMoves(vector<int>& machines) {
int n = machines.size(), ans = 0;
int tot = accumulate(machines.begin(), machines.end(), 0);
if (tot % n != 0)
return -1;
int avg = tot / n;
int right_sum = tot, left_sum = 0;
for (int i = 0; i < n; i++) {
right_sum -= machines[i];
int r_2_l = max(i * avg - left_sum, 0);
int l_2_r = max((n - i - 1) * avg - right_sum, 0);
ans = max(ans, l_2_r + r_2_l);
left_sum += machines[i];
}
return ans;
}
};
为什么答案是:取工作量最大的洗衣机呢?
因为洗衣机可以并行呀
这题不是求最少操作次数吗?还是不太懂!
在最优情况下,工作量做大的洗衣机就是需要的时间呀。
并行!一语惊醒!
可以说是最好的解释了
听了你说的,代码能实现。不过为什么必定存在一个洗衣机,它运送的衣服数量等于答案?这点没想明白。求指教
若不存在一个洗衣机,它运送的衣服数量等于答案。则必定是这种情况,洗衣机A运送了一次,洗衣机B不动;然后洗衣机B运送了一次,洗衣机A不动。但这种情况显然可以并行完成。
“则必定是这种情况,洗衣机A运送了一次,洗衣机B不动;然后洗衣机B运送了一次,洗衣机A不动。” 如果在第一次A运送的时候,B的衣服数量是0,那么无法并行完成啊。
之前的回复可能有些问题,这里本质还是单台洗衣机一次操作只能运送一件衣服,所以找到最大的瓶颈就是答案。