2019-04-19 力扣 887. 雞蛋掉落 困難

前段時間嘗試開始寫了一波簡書,被我的小伙伴嘲笑了一波,說我寫的沒有什么難度,讓我來一道摔雞蛋,今天剛好有空,接受他的挑戰(zhàn)直接來一道困難的雞蛋掉落問題。題目如下:


題目鏈接https://leetcode-cn.com/problems/super-egg-drop/

你將獲得K個雞蛋,并可以使用一棟從1到N共有?N層樓的建筑。

每個蛋的功能都是一樣的,如果一個蛋碎了,你就不能再把它掉下去。

你知道存在樓層F?,滿足0 <= F <= N?任何從高于?F的樓層落下的雞蛋都會碎,從F樓層或比它低的樓層落下的雞蛋都不會破。

每次移動,你可以取一個雞蛋(如果你有完整的雞蛋)并把它從任一樓層X扔下(滿足1 <= X <= N)。

你的目標(biāo)是確切地知道?F?的值是多少。

無論?F?的初始值如何,你確定?F?的值的最小移動次數(shù)是多少?

示例 1:

輸入:K = 1, N = 2輸出:2解釋:雞蛋從 1 樓掉落。如果它碎了,我們肯定知道 F = 0 。否則,雞蛋從 2 樓掉落。如果它碎了,我們肯定知道 F = 1 。如果它沒碎,那么我們肯定知道 F = 2 。因此,在最壞的情況下我們需要移動 2 次以確定 F 是多少。

示例 2:

輸入:K = 2, N = 6輸出:3

示例 3:

輸入:K = 3, N = 14輸出:4


提示:

1 <= K <= 100

1 <= N <= 10000

思路:

這題目第一眼看下去確實沒有很大的思路,題目大概意思是說給你有限個雞蛋(雞蛋摔壞了就沒了),然后讓你在一個N層樓高的樓層去摔,用最少的次數(shù)找到雞蛋在那一層才會被摔碎。

那我們先來屢一下思路,往簡單點想:

假如我們有無限個雞蛋,有100層樓高,是不是就像猜數(shù)字一樣,在1-100里面猜數(shù)字,沒有猜對,主持人會告訴你大了還是小了的游戲(碎了就是大了,沒碎就是小了),那我們肯定無腦選擇中間值去摔,先在50層摔,如果碎了,就在1-49層去再找中間值摔,如果沒碎,就去51-100層找中間值摔。每次折半,我們需要log(100)次也就是7次。

假如我們只有一個雞蛋,有100層樓高,我們還能不能像剛才那樣從50層開始摔呢?很明顯是不能,因為一旦我們從50層開始摔,萬一雞蛋碎了,后面我們就沒有雞蛋可以去摔了,我們承擔(dān)不起雞蛋被摔碎了的風(fēng)險,所以如果只有1個雞蛋,我們被迫只能腳踏實地從第一層開始摔,如果沒有碎,再一層一層往上摔。如果雞蛋在100層才碎,我們最終將會摔100次,所以我們需要的次數(shù)就是100次。

那假如我們有兩個雞蛋,有100層樓高,這就不一樣了,我們有了基本,可以從高一點的樓層摔,如果摔碎了,我們還有一個雞蛋可以再一層一層摔,但是這就有個問題了,從高一點的樓層摔是多高呢?如果從50層摔,碎了,我們要再摔50次,沒碎我們就相當(dāng)于從51-100層摔2個雞蛋,具體的次數(shù)等同于我們有兩個雞蛋,有50層樓高的這樣一種情況,肯定是低于50次的,但是按照總次數(shù)來說肯定還是選擇最壞情況50次,那么這是不是最優(yōu)解呢?會不會從33層摔下去,次數(shù)更低呢?

當(dāng)想到這里,很容易的看出來,當(dāng)碎了和沒碎的情況所需要的次數(shù)相等時(或者是最接近時),次數(shù)更低。那么也就是說我們想要知道從那一層開始摔是最好的,必須一層一層遍歷去判斷。當(dāng)我們遍歷到第10層時,碎了的情況的次數(shù)就等同于(我們只有一個雞蛋【這里考了一道小學(xué)數(shù)學(xué)題:兩個雞蛋碎了一個還有多少個?】,有9層樓高),沒碎的情況就等同于(我們有兩個雞蛋【這里又考了一道小學(xué)數(shù)學(xué)題:兩個雞蛋摔了一個沒碎還有多少個?】,有90層樓高)。當(dāng)分析到這里,我們要求有兩個雞蛋,有100層樓高的情況,就需要知道一個雞蛋9層樓和兩個雞蛋90層樓的解,也就是原題目子問題的解,很明顯的動態(tài)規(guī)劃的思路。

解析:

使用DP去實現(xiàn),按照題目意思定義一個dp[105][10005]數(shù)組,dp[x][y]代表x個雞蛋y層樓的最優(yōu)解。初始化為0。

把x=1的全賦值為y代表只有一個雞蛋的情況下,最優(yōu)解為樓層數(shù)。

然后從x=2開始動態(tài)規(guī)劃求解每一個子問題的最優(yōu)解。

代碼如下:

class Solution {

public:

int dp[105][10005] = { 0 };

int superEggDrop(int K, int N) {

if (K == 1) return N;

if (dp[K][N]) return dp[K][N];

for (int y = 1; y <= N; ++y) dp[1][y] = y;

for (int x = 2; x <= K; ++x)

{

for (int y = 1; y <= N; ++y)

{

int minNUM = y;

for (int i = 1; i <= y; ++i)

{

int temp = std::max(dp[x - 1][i - 1], dp[x][y - i]) + 1;

if (temp < minNUM) minNUM = temp;

}

dp[x][y] = minNUM;

}

}

return dp[K][N];

}

};


優(yōu)化:

通過了所有樣例,但是超時,這是在意料之中,K=100,N=10000這么大的數(shù)據(jù)規(guī)模,每一個子問題的解都要遍歷N遍,時間復(fù)雜度為O(K*N*N),高達(dá)10^10。

那么要怎么優(yōu)化呢?如果要使用動態(tài)規(guī)劃的話,K*N的子問題是無可避免的,我們只能去優(yōu)化求解每個子問題的時間。

剛才我們每次求解子問題都是從i=1遍歷到i=N,那么在這個遍歷過程中,碎了的情況一開始肯定是最小的1次,逐步變大到N次。同時沒碎的情況的次數(shù)肯定是從大到小的一個過程。在這樣有規(guī)律的情況下,我們可以使用二分去優(yōu)化。

優(yōu)化后代碼如下:

class Solution {

public:

int dp[105][10005] = { 0 };

int superEggDrop(int K, int N) {

if (K == 1) return N;

if (dp[K][N]) return dp[K][N];

for (int y = 1; y <= N; ++y) dp[1][y] = y;

for (int x = 2; x <= K; ++x)

{

for (int y = 1; y <= N; ++y)

{

int minNUM = y;

int i = 1;

int j = y;

while (i <= j)

{

int m = i + ((j - i) >> 1);

int broken = dp[x - 1][m - 1];

int enbroken = dp[x][y - m];

int temp = std::max(broken,enbroken) + 1;

if (temp < minNUM) minNUM = temp;

if (broken < enbroken) i = m + 1;

else j = m - 1;

}

dp[x][y] = minNUM;

}

}

return dp[K][N];

}

};


雖然通過了,但是在速度上只擊敗了6%的用戶,說明還有更快的方法。

計算可知動態(tài)規(guī)劃加二分優(yōu)化的時間復(fù)雜度為O(K*N*logN)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在C語言中,五種基本數(shù)據(jù)類型存儲空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 3,993評論 0 2
  • Fortran Best Practices ====================== .. highligh...
    boliecon閱讀 212評論 0 1
  • 一年級語文上冊生字表 生字表一(共400字) 啊(ā)愛(ài)安(ān)岸(àn)爸(bà)八(bā)巴(bā)...
    meychang閱讀 3,134評論 0 6
  • 16年畢業(yè)的,如今已經(jīng)一年了,路是越來越難走,因為自己之前沒去好好努力,嘗到如今的苦果。 初中時候,學(xué)習(xí)一直挺踏實...
    三月公子閱讀 217評論 0 0
  • 突然覺得我長大,屬于我的青春年華在悄悄的溜走。一直以來總覺得自己還小,可已經(jīng)失去了少年的童真;覺得自己還小...
    柒號膽小鬼閱讀 238評論 1 0

友情鏈接更多精彩內(nèi)容