每周力扣题总结
力扣887:鸡蛋掉落
这个视频讲的很详细,由浅入深:
https://www.bilibili.com/video/BV1Lb411q7Ce?from=search&seid=6248980812420132768
接下来记录一下我个人的理解。
假设函数drop(k,n)表示有k个鸡蛋,n层楼时需要扔鸡蛋的次数。
首先,一道动态规划的题目,需要先确立他的(人类能想到的)边界情况,这个题的边界情况有三种:
- 只有一个鸡蛋的时候。因为只有一个鸡蛋的时候,最坏的情况是目标楼层在最高楼,而我需要扔鸡蛋的次数,必须是与最高楼层相等。因为我只有一个鸡蛋,所以如果一开始就从最高楼层扔,万一鸡蛋碎了,那么可能的楼层将会是下面的所有楼层,这样无法保证我能找到那一个目标楼层。所以我只能从一楼、二楼。。。这样一层一层扔,直到找到目标楼层为止。而最坏的情况又是在最高楼层,所以drop(1,n) = n
- 只有一层楼的时候,无论有几个鸡蛋,都只能扔一次,因此drop(k,1) = 1
- 只有0层楼的时候,无论有几个鸡蛋,都不能扔鸡蛋,因此drop(k,0) = 0
那么,这三个边界情况就做好了,接下来我们来看一下,大的作业是怎么样划分为小的作业的。
假设我们需要解决的问题是drop(3,6),我们可以先按照楼层,将情况分为下面的几种:
我手里有三个鸡蛋,如果从6楼扔下去,鸡蛋没碎的话,由于目标楼肯定是在上面,那么我要做的是再往上走,继续扔。但是顶楼就是6楼,所以我不能上了,这表示我只能上6-6=0楼。
如果是从5楼扔下去没有碎,那么我需要往上6-5-0楼。
如果是从4楼扔下去没有碎,那么我需要往上6-4=2楼。
以此类推,可以得到下图所示的情况。
如果鸡蛋碎了的话,因为目标楼层肯定在下层,那么我需要往下走。
如果在6楼扔鸡蛋碎了的话,那么还有5层楼需要检查。
如果在5楼扔鸡蛋碎了的话,那么还有4层楼需要检查。
因此,可以得到下图的情况:
因此,对于drop(K,N)我们需要假设鸡蛋从i(1<=i<=N)楼往下扔且i楼为顶楼的情况,每种情况再划分为鸡蛋碎了和没有碎的情况下。
在这里,我们就已经发现触及到了一些我们得边界情况,比如drop(2,0) drop(3,0)等。以此类推,我们可以将drop(3,6)的情况划分成边界情况求解。下面我们看一下动态规划数组的装填和递推式的推导。
并且在模拟的时候就表示,鸡蛋已经扔了一次了,所以每次模拟完,扔鸡蛋的次数需要加1。
ublic class eggDrop {
public static void main(String[] args) {
System.out.println(solution(2,6));
return;
}
public static int solution(int K, int N) {
int[][] drop = new int[K+1][N+1];
for(int floor=1;floor<=N;floor++) {
drop[1][floor] = floor;
}
for(int egg=1;egg<=K;egg++) {
drop[egg][0] = 0;
drop[egg][1] = 1;
}
//一行一行的填满drop数组
for(int egg=2;egg<=K;egg++) {
for(int floor=2;floor<=N;floor++) {
int minDrop = Integer.MAX_VALUE;
for(int f=1;f<=floor;f++) {
//模拟从每层楼扔下鸡蛋,并且此时floor最大楼层
minDrop = Math.min(minDrop, Math.max(drop[egg][floor-f],drop[egg-1][f-1]));
}
drop[egg][floor] = minDrop+1;
}
}
return drop[K][N];
}
}