517. 超级洗衣机 https://leetcode-cn.com/problems/super-washing-machines/
假设有 n 台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。
在每一步操作中,你可以选择任意 m (1 ≤ m ≤ n) 台洗衣机,与此同时将每台洗衣机的一件衣服送到相邻的一台洗衣机。
给定一个非负整数数组代表从左至右每台洗衣机中的衣物数量,请给出能让所有洗衣机中剩下的衣物的数量相等的最少的操作步数。如果不能使每台洗衣机中衣物的数量相等,则返回 -1。
示例 1:输入: [1,0,5] 输出: 3 解释: 第一步: 1 0 <-- 5 => 1 1 4 第二步: 1 <-- 1 <-- 4 => 2 1 3 第三步: 2 1 <-- 3 => 2 2 2
示例 2:输入: [0,3,0] 输出: 2 解释: 第一步: 0 <-- 3 0 => 1 2 0 第二步: 1 2 --> 0 => 1 1 1
示例 3:输入: [0,2,0] 输出: -1 解释: 不可能让所有三个洗衣机同时剩下相同数量的衣物。
提示:
- n 的范围是 [1, 10000]。
- 在每台超级洗衣机中,衣物数量的范围是 [0, 1e5]。
思路1: 我的理解是像流水一样,多的向少的蔓延,但是如果某个地方水为0,高处的水还没有蔓延到这里,那么这里就耽误了,因此采用逐步蔓延的方法,这个过程也是题目描述过程的真实模拟!
代码如下,在117/120处超时。
class Solution {
public:
bool vist[10000];
int findMinMoves(vector<int>& machines) {
int n=machines.size();
vector<int> d(n-1,0);
int cnt=0,aver;
for(int i=0; i<n; i++)
{
cnt+=machines[i];
}
aver=cnt/n;
if(cnt!=aver*n)
{
cout<<"-1"<<endl;
return -1;
}
cnt=0;
for(int i=0; i<n-1; i++)
{
d[i]=machines[i]-aver+cnt;
cnt=d[i];
}
bool ex;
cnt=0;
do
{ ex=false;
//for(int i=0;i<n;i++) vist[i]=0;
memset(vist,0,sizeof(bool)*n);
for(int i=0; i<n-1; i++)
{
if(d[i]>0&&machines[i]>0&&!vist[i])
{
machines[i]--;
machines[i+1]++;
d[i]--;
ex=true;
vist[i]=true;
}
if(d[i]<0&&machines[i+1]>0&&!vist[i+1])
{
machines[i+1]--;
machines[i]++;
d[i]++;
ex=true;
vist[i+1]=true;
}
}
if(ex) cnt++;
} while(ex);
return cnt;
}
};
思路2:实际上,我上述的担忧是不存在的,当此处为0的水要蔓延,花费的时间肯定比其他水更多的地方花费的时间少,即便此处因为没有水了,耽误了,不影响最大时间,比如,0 0 6,那么第二个0要向第一个移动2个水,但是开始的时候因为第二处没有水,耽误了一个时间,但是6处需要4个时间,2处不影响最大时间。
因此,代码简化如下。 d[i]如果为负数,表示后面要向当前i流动,否则,当前要向后面流动,如果一个既要 向前流动,又要想后流动,那么应该是是前后流动之和,比如0 3 0.这个要特别注意。
class Solution {
public:
bool vist[10000];
int findMinMoves(vector<int>& machines) {
int n=machines.size();
vector<int> d(n-1,0);
//vector<int> vist(n,0);
int cnt=0,aver;
for(int i=0; i<n; i++)
{
cnt+=machines[i];
}
aver=cnt/n;
if(cnt!=aver*n)
{
cout<<"-1"<<endl;
return -1;
}
cnt=0;
int imax=0;
for(int i=0; i<n-1; i++)
{
d[i]=machines[i]-aver+cnt;
cnt=d[i];
imax=max(imax,abs(cnt));
cout<<d[i]<<" ";
}
for(int i=1; i<n-1; i++)
{
if(d[i-1]<0 && d[i]>0)
imax=max(imax,abs(d[i])+abs(d[i-1]));
}
return imax;
}
};
思路3. 优秀例子
class Solution {
public:
int findMinMoves(vector<int>& machines) {
long long sum1 = accumulate(machines.begin(),machines.end(),0);
if(sum1%(int)machines.size()!=0)return -1;
int cnt=0,aver=sum1/(int)machines.size();
int bla=0;
for(auto num:machines){
bla+=num-aver;
cnt=max(cnt,max(num-aver,abs(bla)));
}
return cnt;
}
};