基础解法前面写过,链接如下:
Leecode高楼抛鸡蛋 --递归回溯法和动态规划法
代码如下
class ThrowEgg {
int[][] memo;
// int count;
public static void main(String[] args) {
ThrowEgg te = new ThrowEgg();
// System.out.println(ta.innerLoop(1, 2));
System.out.println(te.outerLoop(2, 6));
// System.out.println(te.outerLoop(3, 14));
// System.out.println(te.count);
}
public int outerLoop(int k, int n) {
memo = new int[k + 1][n + 1];
return innerLoop(k, n);
}
// 用二分搜索查找谷底。
public int innerLoop(int k, int n) {
if (k == 1) return n;
if (n == 0) return 0;
if (memo[k][n] != 0) return memo[k][n];
int res = Integer.MAX_VALUE;
int le = 1, ri = n;
while (le <= ri) {
int mid = (le + ri) / 2;
int broken = innerLoop(k - 1, mid - 1); //碎
int non_broken = innerLoop(k, n - mid); //不碎
// res = (碎,没碎)+1,加1是因为不管碎没碎,我都抛了一次
// 谁大谁 +1的原因是因为要找 剩余楼层最多的那个。(保证最坏情况)
if (broken > non_broken) {
ri = mid - 1; //这个和递归树无关,和那张单调图有关
res = Math.min(res, broken + 1);
} else {
le = mid + 1; //这个和递归树无关,和那张单调图有关
res = Math.min(res, non_broken + 1);
}
// count++;
}
memo[k][n] = res;
return res;
}
}
代码解释
这个解法其实是两个部分的耦合,应该把这两部分分开来思考。否则容易两部分交叉,给思考增加难度
分成了这两部分:
1.递归树(目的是解决min(max))
2.单调图(目的是解决先从第几楼开始抛)
第一部分需要的元素:
k鸡蛋数,
n最高楼层,
mid:从第mid层抛鸡蛋。
递归树元素(k,n):最高层是n,有k个鸡蛋,找出f的最小次数
第二部分需要的元素:le,ri,mid
两者共有的元素 broken non_broken
递归树部分就不分析了,看下面的图自己理解。
分析一下第二部分
只看第一层,
一开始le =1 , ri=6 所以mid=3,此时broken<non_broken,即黄线>蓝线,此时把le=mid+1
然后到了 le = 4, ri=6 ,所以mid=5,此时non_broken>broken,即蓝线>黄线,还是没有重合。那么再度逼近。
总结:变更le 和 ri的根本目的是让横坐标朝交叉点的横坐标无线接近