假设有 n 台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。
在每一步操作中,你可以选择任意 m (1 <= m <= n) 台洗衣机,与此同时将每台洗衣机的一件衣服送到相邻的一台洗衣机。
给定一个整数数组 machines 代表从左至右每台洗衣机中的衣物数量,请给出能让所有洗衣机中剩下的衣物的数量相等的 最少的操作步数。如果不能使每台洗衣机中衣物的数量相等,则返回 -1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/super-washing-machines
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
### 解题思路
左侧第一个数会出现以下几种情况:
1.需要右方提供数值;
2.需要给右方数值;
3.不需要动;
后面除了倒数第一个数会有以下情况:
1.被左侧拿数值,减去数值后小于或等于平均数值不需要多余处理,如果多则需要步骤叠加处理;
2.被左侧给数值,加上数值,无论怎样都不用特殊操作,因为只往右边传递数值,不会出现步骤叠加。
关键问题在于需要给左右都提供数值的数字,如果出现多个如何平衡的问题。
一步一步循序渐进,哪里有问题调试哪里,总会成功的uu们。
可以用{0,0,10,0,0,0,10,0,0,0},{0,3,0},{0,0,11,5},{11,0,0,5},{0,4,12,0}几个例子帮助理解。
### 代码
```cpp
class Solution {
public:
int findMinMoves(vector<int>& machines) {
// 首先不用多说了先算平均值和看是否合法(开胃菜)
int sum = 0, ret = 0;
for (auto m : machines) {
sum += m;
}
int average = sum / machines.size();
if (sum % machines.size() != 0) {
return -1;
}
// 从头到尾遍历一遍,使所有值都变为平均值并记录操作数
for (int i = 0; i < machines.size()-1; ++i) {
// 用来记录当前操作所需要的最大步数为了给最大值服务的
// 如果最大值需要给左右两个方向都提供数字,则需要叠加
// now用来解决如果有多个最大值的所出现的问题
int now = -1;
// kkk用来表示当前数值与平均数的差值
int kkk = abs(average - machines[i]);
// 如果不等于就处理,等于直接跳过
if (kkk > 0 ) {
// 差值是a则至少需要a步
if (kkk > ret) {
ret = kkk;
}
// 下面是平衡操作使所有数值都变为平均值
// 如果大于平均值则当前值减去差值,后面的值加上差值
// 因为从头开始不用考虑当前值前面的所有值
if (machines[i] > average) {
machines[i] -= kkk;
machines[i+1] += kkk;
}
// 如果当前值小于平均值,则当前值加上差值,后面的值减去差值
else {
machines[i] += kkk;
machines[i+1] -= kkk;
// 如果后面的值减去差值后还大于平均值,则还需要给右边的数数值
// 由于一次只能给一个数值,所以这里需要叠加次数
// 这块有点难理解,可以自己画一个例子辅助理解
// 本质上是找到最大的值然后计算所需要的最小操作数
if (machines[i + 1] > average) {
// uuu为后1数与平局数的差值
int uuu = machines[i + 1] - average;
// 由于步数不需要累加,就是说每一步操作之与上一步操作有关,
// 因为可以同时移动,now就等于当前所需要操作步数
now = kkk + uuu;
// 如果当前也就是后面这个数所需要的操作步数大于之前的,替换
if (now > ret) {
ret = now;
}
}
}
}
}
return ret;
}
};