タイトル説明
https://leetcode-cn.com/problems/super-egg-drop/
解決
私はそれを理解することができません、そして私はトピックをよく理解していません。最後に、問題解決の分析を見に行きました。どの値fが0 <= f <= Nにあるかに関係なく、特定のオペランドがそれを見つけて、このオペランドの最小値を見つけることが必要であることを知っています。
1.動的計画
知っておくべきこと:
- 卵が1つしかない場合、インタビューの下部から上部まで、一度に1つのレイヤーしか持つことができず、fのオペランドを知ることができます。つまり、if(k == 1)return n;
- フロアが0の場合、卵は必要ありません。f= 0であり、オペランドも0です。つまり、if(n == 0)は0を返します。
- その他の状況:卵をi階に落とした場合、卵
が壊れた場合、fは0 <= f <= i-1階にのみ存在する可能性があり、見つける必要のある階数はiです。 -1;
壊れたiがない場合、fはレイヤーi + 1 <= f <= nにある可能性があり、ここで見つける必要があるレイヤーの数はniです。
つまり、サブがあります。 -問題のプロパティ。 - 最悪の場合:nフロアが下から上にテストされ、n回かかります
- 私たちの目標は、fを確認できなければならないすべての可能な時間の中で最小の値を見つけることです。たとえば、9つの操作でfを確認でき、8つの操作でfを確認できます。可能性は2つだけで、8を返します。
上記のアイデアに従って再帰コードを記述します。
public int calcF(int k,int n){
if(k==1) return n;
if(n==0) return 0;
int res = n;//最坏的可能次数
for(int i=1;i<=n;i++){
res = Math.min(res,
Math.max(calcF(k-1,i-1),calcF(k,n-i))+1
);
}
return res;
}
重要なのは、これを理解することです。
res = Math.min(res,
Math.max(calcF(k-1,i-1),calcF(k,n-i))+1//我们这里坏,没坏种情况一定要取最大的哪个保证可以确认f的 。
);//最后是所有可以确认f的次数中的最少值
時間計算量はO(k * N 2)であり、渡すことはできません。複雑さを軽減する必要があります。
2.覚書の動的計画
メモを使用する場合(重複するサブ問題の一部のみを減らすことができます)、複雑さは同じままです。
class Solution {
int [][]memo;
public int superEggDrop(int k, int n) {
memo = new int[k+1][n+1];
for(int[]a:memo){
Arrays.fill(a,-1);
}
return calcF(k,n);
}
public int calcF(int k,int n){
//返回的f是最坏情况下的最小操作次数
if(k==1) {
memo[k][n] = n;//只有一个鸡蛋,只能一层一层的从底部向上试
}
if(n==0){
memo[k][n] = n;
}// return 0;//操作不需要知道
if(memo[k][n]!=-1){
return memo[k][n];
}
//鸡蛋数必然不为0
int res = n;//至少n次坏-----------这里一定是局部,表示当前结果的最少操作数,
for(int i=1;i<=n;i++){
//一层一层的试,如果第i层鸡蛋坏了,则k-1,搜索楼层为i-1
//如果没坏,则鸡蛋数不变,楼层的搜索仅需要利用剩下的鸡蛋搜索上面的n-i层
res = Math.min(res,
Math.max(calcF(k,n-i),
calcF(k-1,i-1)
)+1
);
}
memo[k][n] = res;
return res;
}
}
3.動的計画法と二分探索-O(kNlogN)
参照問題の解決策:https://leetcode-cn.com/problems/super-egg-drop/solution/ji-dan-diao-luo-by-leetcode-solution- 2 /
再帰方程式の特性を使用して、現在のN層操作を最小回数にするi層の範囲を見つけることは、0から "Nまでの線形探索ではなく、二分探索です。
class Solution {
int [][]memo;
public int superEggDrop(int k, int n) {
memo = new int[k+1][n+1];
for(int[]a:memo){
Arrays.fill(a,-1);
}
return calcF(k,n);
}
public int calcF(int k,int n){
//返回的f是最坏情况下的最小操作次数
if(k==1) {
memo[k][n] = n;//只有一个鸡蛋,只能一层一层的从底部向上试
}
if(n==0){
memo[k][n] = n;
}// return 0;//操作不需要知道
if(memo[k][n]!=-1){
return memo[k][n];
}
//使用二分查找:
int left = 1,right=n;
while(left+1<right){
//两者差1,找到最大满足T1(x)<T2()x)
int mid = (left+right)/2;
int t1 = calcF(k-1,mid-1);
int t2 = calcF(k,n-mid);
if(t1<t2){
left=mid;
}else if(t1>t2){
right=mid;
}else{
left = right = mid;
}
}
int res = 1+Math.min(//注意不要忘了操作数加1,因为鸡蛋碎或者不碎都要加1
//在left这边
Math.max(calcF(k-1,left-1),calcF(k,n-left)),
//在right这边
Math.max(calcF(k-1,right-1),calcF(k,n-right))
);
memo[k][n] = res;
return res;
}
}
上級1:状態遷移方程式を書き直す
スーパーボスによって書かれたソリューションへの完全なリファレンス:https://leetcode-cn.com/problems/super-egg-drop/solution/887-by-ikaruga/
class Solution {
int [][]memo;
public int superEggDrop(int k, int n) {
int T=1;
while(calcF(k,T)<n+1) T++;
return T;
}
//T是机会数
public int calcF(int k,int T){
if(k==1||T==1) return T+1;//只有一次机会或者一个蛋,只能确认T+1个F
return calcF(k-1,T-1)+calcF(k,T-1);//消耗一次机会,蛋可以碎或者不碎
}
}