Leetcode 貪心:差值調整

一隻老風鈴發表於2020-10-11

題目描述

有n個箱子,第i個箱子一開始有ai​個球,你可以進行最多k次操作,每次操作可以從一個箱子拿走一個球或者放入一個球。第i個箱子最多能裝wi​個球,裝滿了之後不能再往這個箱子裡面放球。如果一個箱子為空,就不能從裡面拿球。

相鄰箱子的球的數量的差的平方中的最大值為x,求進行最多k次操作之後x最小可以是多少。

輸入

5,4,[12,4,7,9,1],[15,15,15,15,15]

輸出

36

往第2個箱子放2個球,往第5個箱子放2個球得到[12,6,7,9,3],此時相鄰箱子的球數差值為[-6,1,2,-6],平方後為[36,1,4,36],其中最大值為36

 

【思路】

本題的問題是使得經過一定的次數,使得相鄰的差值平方儘可能小(即:所有數儘可能靠近)

貪心策略:

每一輪找到相鄰差值最大的那兩個數a[index]=>a[index+1],有兩種策略:較大的那個數減少,或者較小的那個數增大。

具體的策略是:

如果當前a[index]<a[index+1]即 是增大的:分三大類情況:

  1. 當前index==0  第一二個數:那麼分析其後一組是否為增大或減少,選擇相應的策略
  2. 當前index==n-2 最後兩個數index-2 index-1   那麼分析前面一組是否為增大或減少,選擇相應的策略
  3. 其它情況,需要同時分析前面一組,後面一組的情況,特別點(如三組都增大:需要比較斜率大小)

如果當前a[index]<a[index+1]即 是減少的 ,同上所述

優化策略:

由於有w[i]上限限制,當發現較小的那個數a[index]==w[index]  達到上限,那麼直接較大的那個數減少即可。

實現程式碼:



int solve(int n, int k, vector<int>& a, vector<int>& w) {

    for(int i=0;i<k;i++)  //總共需要調整k次
    {

        //首先計算出當前相鄰差值最大的index
        vector<int> dst(n-1,0);
        int index=-1;
        int _max_dst=0;
        for(int i=0;i<n-1;i++)
        {
            dst[i]=a[i+1]-a[i];//dst[i]
            if(dst[i]*dst[i]>_max_dst)
            {
                _max_dst=dst[i]*dst[i];
                index=i;
            }
        }
        //那麼 相鄰值相差最大的為 a[index]和a[index+1]
        if(index==-1)
            continue;
        if(dst[index]>0)  //若該組為增大    那麼兩種策略:前面的數增大  或者  後面的數減少
        {
            if(index==n-2)  //如果這是最後兩個數  0=>n-1  dst[n-2]=a[n-1]-a[n-2]
            {
                if(index-1>=0 && dst[index-1]<0)  //如果前面一組是減少的
                {
                    if(a[index]<w[index]) //優先選擇當前Index++
                    {
                        a[index]++;
                    } else{  //否則後面那個數 減少

                             a[index+1]--;
                    }
                } else
                {
                        a[index+1]--;//那麼直接最後那個數減少
                }

            }
            else if(index==0)  //第一、二個數
            {
                if( (index+1<=n-2 && dst[index+1]<0) || a[index]==w[index]) //後面一組是減少的  或者較小的那個數不能增大了 那麼直接index+1減少
                {
                    a[index+1]--;
                } else
                {
                    a[index]++; //後面一組也是增大  那麼當前第一個數 增大
                }

            } else
            {
                if(dst[index+1]<0) //後面一組是減少的 那麼直接index+1減少
                    a[index+1]--;
                else
                {
                    if(dst[index-1]<0) //前面一組是減少的
                    {
                        if(a[index]<w[index])      //優先選擇index++
                            a[index]++;
                        else                    //前面一個數不能增大  那麼只能後面的數減少
                            a[index+1]--;
                    } else  //三組都是增大的
                    {
                        if(dst[index-1]<dst[index+1] || a[index]==w[index])  //前面那組 增大趨勢更大
                            a[index+1]--;
                        else
                        {
                                a[index]++;
                        }
                    }
                }
            }

        } else  //當前a[index] => a[index+1]是減少的
        {


            if(index==n-2)  //如果這是最後兩個數
            {
                if((index-1>=0 && dst[index-1]>0) || a[index+1]==w[index+1])  //如果前面一組是增大的  或者較小的那個數不能增大
                {
                    a[index]--;
                } else
                {
                    a[index+1]++;//那麼直接最後那個數減少
                }

            }
            else if(index==0)  //第一、二個數
            {
                if((index+1<=n-2 && dst[index+1]<0  ) || a[index+1]==w[index+1]) //後面一組是減少的  或者較小的那個數不能增大了
                {
                    a[index]--;//那麼只能較大的那個數減少
                } else
                {
                    a[index+1]++;
                }

            } else
            {
                if(index+1<=n-2 && dst[index+1]>0) //後面一組是增大的
                {
                    if(a[index+1]<w[index+1])
                        a[index+1]++;  //較小的那個數增大
                    else
                        a[index]--;
                }
                else
                {
                    if(index-1>=0 && dst[index-1]>0) //前面一組是增大的
                    {
                        a[index]--;//直接較大的數減少
                    } else  //三組都是減少的   那麼需要權衡  前後兩組dst
                    {
                        if(dst[index-1]>dst[index+1] || a[index+1]==w[index+1])  //同時如果較小的那個數不能增大  那麼也直接減少較大的數
                            a[index]--;
                        else
                        {
                            a[index+1]++;
                        }
                    }
                }
            }

        }
    }
    int res=0;
    for(int i=0;i<n-1;i++)
    {
        res=max(res,(a[i+1]-a[i])*(a[i+1]-a[i]));
    }
    return res;

}

驗證程式碼:


int main()
{

    vector<int> a={12,4,7,9,1};
    vector<int> b={15,15,15,15,15};
    cout<<solve(5,4,a,b)<<endl;

}

 

 

相關文章