|
|
package class42;
|
|
|
|
|
|
// leetcode测试链接:https://leetcode.com/problems/super-egg-drop
|
|
|
// 方法1和方法2会超时
|
|
|
// 方法3勉强通过
|
|
|
// 方法4打败100%
|
|
|
// 方法5打败100%,方法5是在方法4的基础上做了进一步的常数优化
|
|
|
public class Code02_ThrowChessPiecesProblem {
|
|
|
|
|
|
public static int superEggDrop1(int kChess, int nLevel) {
|
|
|
if (nLevel < 1 || kChess < 1) {
|
|
|
return 0;
|
|
|
}
|
|
|
return Process1(nLevel, kChess);
|
|
|
}
|
|
|
|
|
|
// rest还剩多少层楼需要去验证
|
|
|
// k还有多少颗棋子能够使用
|
|
|
// 一定要验证出最高的不会碎的楼层!但是每次都是坏运气。
|
|
|
// 返回至少需要扔几次?
|
|
|
public static int Process1(int rest, int k) {
|
|
|
if (rest == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
if (k == 1) {
|
|
|
return rest;
|
|
|
}
|
|
|
int min = Integer.MAX_VALUE;
|
|
|
for (int i = 1; i != rest + 1; i++) { // 第一次扔的时候,仍在了i层
|
|
|
min = Math.min(min, Math.max(Process1(i - 1, k - 1), Process1(rest - i, k)));
|
|
|
}
|
|
|
return min + 1;
|
|
|
}
|
|
|
|
|
|
public static int superEggDrop2(int kChess, int nLevel) {
|
|
|
if (nLevel < 1 || kChess < 1) {
|
|
|
return 0;
|
|
|
}
|
|
|
if (kChess == 1) {
|
|
|
return nLevel;
|
|
|
}
|
|
|
int[][] dp = new int[nLevel + 1][kChess + 1];
|
|
|
for (int i = 1; i != dp.length; i++) {
|
|
|
dp[i][1] = i;
|
|
|
}
|
|
|
for (int i = 1; i != dp.length; i++) {
|
|
|
for (int j = 2; j != dp[0].length; j++) {
|
|
|
int min = Integer.MAX_VALUE;
|
|
|
for (int k = 1; k != i + 1; k++) {
|
|
|
min = Math.min(min, Math.max(dp[k - 1][j - 1], dp[i - k][j]));
|
|
|
}
|
|
|
dp[i][j] = min + 1;
|
|
|
}
|
|
|
}
|
|
|
return dp[nLevel][kChess];
|
|
|
}
|
|
|
|
|
|
public static int superEggDrop3(int kChess, int nLevel) {
|
|
|
if (nLevel < 1 || kChess < 1) {
|
|
|
return 0;
|
|
|
}
|
|
|
if (kChess == 1) {
|
|
|
return nLevel;
|
|
|
}
|
|
|
int[][] dp = new int[nLevel + 1][kChess + 1];
|
|
|
for (int i = 1; i != dp.length; i++) {
|
|
|
dp[i][1] = i;
|
|
|
}
|
|
|
int[][] best = new int[nLevel + 1][kChess + 1];
|
|
|
for (int i = 1; i != dp[0].length; i++) {
|
|
|
dp[1][i] = 1;
|
|
|
best[1][i] = 1;
|
|
|
}
|
|
|
for (int i = 2; i < nLevel + 1; i++) {
|
|
|
for (int j = kChess; j > 1; j--) {
|
|
|
int ans = Integer.MAX_VALUE;
|
|
|
int bestChoose = -1;
|
|
|
int down = best[i - 1][j];
|
|
|
int up = j == kChess ? i : best[i][j + 1];
|
|
|
for (int first = down; first <= up; first++) {
|
|
|
int cur = Math.max(dp[first - 1][j - 1], dp[i - first][j]);
|
|
|
if (cur <= ans) {
|
|
|
ans = cur;
|
|
|
bestChoose = first;
|
|
|
}
|
|
|
}
|
|
|
dp[i][j] = ans + 1;
|
|
|
best[i][j] = bestChoose;
|
|
|
}
|
|
|
}
|
|
|
return dp[nLevel][kChess];
|
|
|
}
|
|
|
|
|
|
public static int superEggDrop4(int kChess, int nLevel) {
|
|
|
if (nLevel < 1 || kChess < 1) {
|
|
|
return 0;
|
|
|
}
|
|
|
int[] dp = new int[kChess];
|
|
|
int res = 0;
|
|
|
while (true) {
|
|
|
res++;
|
|
|
int previous = 0;
|
|
|
for (int i = 0; i < dp.length; i++) {
|
|
|
int tmp = dp[i];
|
|
|
dp[i] = dp[i] + previous + 1;
|
|
|
previous = tmp;
|
|
|
if (dp[i] >= nLevel) {
|
|
|
return res;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public static int superEggDrop5(int kChess, int nLevel) {
|
|
|
if (nLevel < 1 || kChess < 1) {
|
|
|
return 0;
|
|
|
}
|
|
|
int bsTimes = log2N(nLevel) + 1;
|
|
|
if (kChess >= bsTimes) {
|
|
|
return bsTimes;
|
|
|
}
|
|
|
int[] dp = new int[kChess];
|
|
|
int res = 0;
|
|
|
while (true) {
|
|
|
res++;
|
|
|
int previous = 0;
|
|
|
for (int i = 0; i < dp.length; i++) {
|
|
|
int tmp = dp[i];
|
|
|
dp[i] = dp[i] + previous + 1;
|
|
|
previous = tmp;
|
|
|
if (dp[i] >= nLevel) {
|
|
|
return res;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public static int log2N(int n) {
|
|
|
int res = -1;
|
|
|
while (n != 0) {
|
|
|
res++;
|
|
|
n >>>= 1;
|
|
|
}
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
int maxN = 500;
|
|
|
int maxK = 30;
|
|
|
int testTime = 1000;
|
|
|
System.out.println("测试开始");
|
|
|
for (int i = 0; i < testTime; i++) {
|
|
|
int N = (int) (Math.random() * maxN) + 1;
|
|
|
int K = (int) (Math.random() * maxK) + 1;
|
|
|
int ans2 = superEggDrop2(K, N);
|
|
|
int ans3 = superEggDrop3(K, N);
|
|
|
int ans4 = superEggDrop4(K, N);
|
|
|
int ans5 = superEggDrop5(K, N);
|
|
|
if (ans2 != ans3 || ans4 != ans5 || ans2 != ans4) {
|
|
|
System.out.println("出错了!");
|
|
|
}
|
|
|
}
|
|
|
System.out.println("测试结束");
|
|
|
}
|
|
|
|
|
|
}
|