开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情
517. 超级洗衣机
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/su…
假设有 n 台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。
在每一步操作中,你可以选择任意 m (1 <= m <= n) 台洗衣机,与此同时将每台洗衣机的一件衣服送到相邻的一台洗衣机。
给定一个整数数组 machines 代表从左至右每台洗衣机中的衣物数量,请给出能让所有洗衣机中剩下的衣物的数量相等的 最少的操作步数 。如果不能使每台洗衣机中衣物的数量相等,则返回 -1 。
示例 1:
输入:machines = [1,0,5] 输出:3 解释: 第一步: 1 0 <-- 5 => 1 1 4 第二步: 1 <-- 1 <-- 4 => 2 1 3
第三步: 2 1 <-- 3 => 2 2 2
示例 2:
输入:machines = [0,3,0] 输出:2 解释: 第一步: 0 <-- 3 0 => 1 2 0
第二步: 1 2 --> 0 => 1 1 1
示例 3:
输入:machines = [0,2,0] 输出:-1 解释: 不可能让所有三个洗衣机同时剩下相同数量的衣物。
提示:
- n == machines.length
解法
- 贪心算法:
num代表什么: 该洗衣机达到平衡需要增加或减少的数量 sum代表什么: 前i个总共需要移动的次数 为什么max(abs(sum), num)的num不用取绝对值 num好理解,就是要达到平衡需要增加(减少)的数量,难点就是sum的理解。
我们可以先考虑如果去掉题中的只能相邻之间操作,那么操作次数就是所有的num中的最大值,因为只要把需要减少的num分发给需要增加的num即可,根据贪心,最大需要减少的num都达到平衡了,其他需要减少的肯定也达到平衡了。
至于为什么不是所有num绝对值的最大值,是因为num为负数,代表需要缺少的数,但是缺少的是可以多个(需要减少的)同时向这个里增加的,这也是疑问3的原因
再回到这道题中的条件:只能相邻之间操作,那么能不能直接把需要减少的给到需要增加的里呢,答案是可以。
举个例子:
可以看到也是操作一步就可以,那答案岂不是和上边的假设一样了。显然不是的,要不咋是困难级别呢。肯定有其他情况需要考虑。
从上图中其实可以发现一个问题,5虽然可以一次操作给一个给到1,但是其中经过了很多步骤,4、3、2也参与其中了,那么本来就多一个的4岂不是浪费了一次机会来减少自己的机会?**【看似我不增也不减,但是我少了一次调整的机会】**所以就引入了sum这个变量,代表的是到目前这个下标(i)为止,0~i需要增加(减少)的总次数。
还拿上边的例子,i=0时,sum=2,i=1时,sum=3,代表前两个组成的组A多三个需要给到后三个组成的组B,因为要给到组B,都需要经过i,所以i每次只能干一件事,所以sum=3,就需要经过3次调整。【负数也是一样的,因为最后能达到平衡,组A的sum值+组B的sum值一定等于0,所以分析一种情况即可】
这样的话随后的结果岂不是等于max(abs(sum)) (sum: i=>0~n-1)
我们还漏了一种情况,那就是万一某个值特别大(某个num>sum),造成组A的sum值很大
举个例子:
从上边的列子可以看到,组A除了要给组B 5个(主要是11给的),还需要在组内达到平衡。由于每个只能操作一次,所以需要操作的次数就是7.
所以最终结果就是max(abs(sum), num)
- python
class Solution:
def findMinMoves(self, machines: List[int]) -> int:
total = sum(machines)
n = len(machines)
if total % n: # 无法均分
return -1
avg = total // n
ans, sums = 0, 0 # ans 表示最终需要的次数, sums表示左边需要移动的次数
for num in machines:
num -= avg
sums += num
ans = max(ans, abs(sums), num)
return ans
- c++
class Solution {
public:
int findMinMoves(vector<int>& machines) {
int total = accumulate(machines.begin(), machines.end(), 0);
int n = machines.size();
if (total % n)
{return -1;}
int avg = total / n;
int ans = 0, sums = 0;
for(int num: machines)
{
num -= avg;
sums += num;
ans = max(ans, max(abs(sums), num));
}
return ans;
}
};
复杂度分析
-
时间复杂度:O(n),其中 n 是数组machines 的长度。
-
空间复杂度:O(1)。只需要常数的空间存放若干变量。