leetCode----517. 超级洗衣机[1]

517. 超级洗衣机 https://leetcode-cn.com/problems/super-washing-machines/

假设有 台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。

每一步操作中,你可以选择任意 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 解释: 不可能让所有三个洗衣机同时剩下相同数量的衣物。

提示:

  1. n 的范围是 [1, 10000]。
  2. 在每台超级洗衣机中,衣物数量的范围是 [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;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值