傳說中的經典面試題
李永樂老師的B站講解
題目鏈接
寫完超時的那一刻我是崩潰的
雖然我承認這個解法的時間複雜度高達,但是解出來就不容易了啊QAQ。
初始化
只有一層樓時,只需要一步;只有一個蛋時,只能一層層向上試,次數=N。
遞歸
dp[k][n]=min(dp[k][n],max(dp[k-1][j-1],dp[k][n-j])+1);
j爲嘗試的樓數,如果碎了下一步嘗試dp[k-1][j-1],如果沒碎下一步嘗試dp[k][n-j]
class Solution {
public:
int superEggDrop(int K, int N) {
//dp[k][n]表示k個雞蛋,n層樓
vector<vector<int>> dp(K+1,vector<int>(N+1,0));
for(int n=1;n<=N;n++)
dp[1][n]=n;
for(int k=1;k<=K;k++)
dp[k][1]=1;
for(int n=2;n<=N;n++)
{
for(int k=2;k<=K;k++)
{
dp[k][n]=N;
for(int j=n;j>=1;j--)
dp[k][n]=min(dp[k][n],max(dp[k-1][j-1],dp[k][n-j])+1);
}
}
return dp[K][N];
}
};
二分查找優化版
對於
1~n
中尋找最佳的嘗試點j
這個問題可以使用二分優化。
我們知道對於相同的k,如果樓層越低,值越低。
因爲broken=dp[k-1][j-1];
因此隨着j++,broken單調不減,呈現上升趨勢。
同理noBroken=dp[k][n-j];
呈現下降趨勢。
因此兩者越接近,max後值越小,因此可以使用二分搜索確定最佳的j
class Solution {
public:
int superEggDrop(int K, int N) {
//dp[k][n]表示k個雞蛋,n層樓
vector<vector<int>> dp(K+1,vector<int>(N+1,N));
int lf,rt,mid,broken,noBroken;
for(int n=1;n<=N;n++)
{
dp[0][n]=0;
dp[1][n]=n;
}
for(int k=1;k<=K;k++)
{
dp[k][0]=0;
dp[k][1]=1;
}
for(int n=2;n<=N;n++)
{
for(int k=2;k<=K;k++)
{
lf=1,rt=n;
while(lf<=rt)
{
mid=lf+(rt-lf)/2;
broken=dp[k-1][mid-1];
noBroken=dp[k][n-mid];
if(broken==noBroken)
break;
else if(broken>noBroken)
rt=mid-1;
else
lf=mid+1;
}
dp[k][n]=min(dp[k][n],max(broken,noBroken)+1);
}
}
return dp[K][N];
}
};
遞歸最香了(佔位,明天填坑)