2019-04-19 力扣 887. 鸡蛋掉落 困难

前段时间尝试开始写了一波简书,被我的小伙伴嘲笑了一波,说我写的没有什么难度,让我来一道摔鸡蛋,今天刚好有空,接受他的挑战直接来一道困难的鸡蛋掉落问题。题目如下:


题目链接https://leetcode-cn.com/problems/super-egg-drop/

你将获得K个鸡蛋,并可以使用一栋从1到N共有 N层楼的建筑。

每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。

你知道存在楼层F ,满足0 <= F <= N 任何从高于 F的楼层落下的鸡蛋都会碎,从F楼层或比它低的楼层落下的鸡蛋都不会破。

每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层X扔下(满足1 <= X <= N)。

你的目标是确切地知道 F 的值是多少。

无论 F 的初始值如何,你确定 F 的值的最小移动次数是多少?

示例 1:

输入:K = 1, N = 2输出:2解释:鸡蛋从 1 楼掉落。如果它碎了,我们肯定知道 F = 0 。否则,鸡蛋从 2 楼掉落。如果它碎了,我们肯定知道 F = 1 。如果它没碎,那么我们肯定知道 F = 2 。因此,在最坏的情况下我们需要移动 2 次以确定 F 是多少。

示例 2:

输入:K = 2, N = 6输出:3

示例 3:

输入:K = 3, N = 14输出:4


提示:

1 <= K <= 100

1 <= N <= 10000

思路:

这题目第一眼看下去确实没有很大的思路,题目大概意思是说给你有限个鸡蛋(鸡蛋摔坏了就没了),然后让你在一个N层楼高的楼层去摔,用最少的次数找到鸡蛋在那一层才会被摔碎。

那我们先来屡一下思路,往简单点想:

假如我们有无限个鸡蛋,有100层楼高,是不是就像猜数字一样,在1-100里面猜数字,没有猜对,主持人会告诉你大了还是小了的游戏(碎了就是大了,没碎就是小了),那我们肯定无脑选择中间值去摔,先在50层摔,如果碎了,就在1-49层去再找中间值摔,如果没碎,就去51-100层找中间值摔。每次折半,我们需要log(100)次也就是7次。

假如我们只有一个鸡蛋,有100层楼高,我们还能不能像刚才那样从50层开始摔呢?很明显是不能,因为一旦我们从50层开始摔,万一鸡蛋碎了,后面我们就没有鸡蛋可以去摔了,我们承担不起鸡蛋被摔碎了的风险,所以如果只有1个鸡蛋,我们被迫只能脚踏实地从第一层开始摔,如果没有碎,再一层一层往上摔。如果鸡蛋在100层才碎,我们最终将会摔100次,所以我们需要的次数就是100次。

那假如我们有两个鸡蛋,有100层楼高,这就不一样了,我们有了基本,可以从高一点的楼层摔,如果摔碎了,我们还有一个鸡蛋可以再一层一层摔,但是这就有个问题了,从高一点的楼层摔是多高呢?如果从50层摔,碎了,我们要再摔50次,没碎我们就相当于从51-100层摔2个鸡蛋,具体的次数等同于我们有两个鸡蛋,有50层楼高的这样一种情况,肯定是低于50次的,但是按照总次数来说肯定还是选择最坏情况50次,那么这是不是最优解呢?会不会从33层摔下去,次数更低呢?

当想到这里,很容易的看出来,当碎了和没碎的情况所需要的次数相等时(或者是最接近时),次数更低。那么也就是说我们想要知道从那一层开始摔是最好的,必须一层一层遍历去判断。当我们遍历到第10层时,碎了的情况的次数就等同于(我们只有一个鸡蛋【这里考了一道小学数学题:两个鸡蛋碎了一个还有多少个?】,有9层楼高),没碎的情况就等同于(我们有两个鸡蛋【这里又考了一道小学数学题:两个鸡蛋摔了一个没碎还有多少个?】,有90层楼高)。当分析到这里,我们要求有两个鸡蛋,有100层楼高的情况,就需要知道一个鸡蛋9层楼和两个鸡蛋90层楼的解,也就是原题目子问题的解,很明显的动态规划的思路。

解析:

使用DP去实现,按照题目意思定义一个dp[105][10005]数组,dp[x][y]代表x个鸡蛋y层楼的最优解。初始化为0。

把x=1的全赋值为y代表只有一个鸡蛋的情况下,最优解为楼层数。

然后从x=2开始动态规划求解每一个子问题的最优解。

代码如下:

class Solution {

public:

int dp[105][10005] = { 0 };

int superEggDrop(int K, int N) {

if (K == 1) return N;

if (dp[K][N]) return dp[K][N];

for (int y = 1; y <= N; ++y) dp[1][y] = y;

for (int x = 2; x <= K; ++x)

{

for (int y = 1; y <= N; ++y)

{

int minNUM = y;

for (int i = 1; i <= y; ++i)

{

int temp = std::max(dp[x - 1][i - 1], dp[x][y - i]) + 1;

if (temp < minNUM) minNUM = temp;

}

dp[x][y] = minNUM;

}

}

return dp[K][N];

}

};


优化:

通过了所有样例,但是超时,这是在意料之中,K=100,N=10000这么大的数据规模,每一个子问题的解都要遍历N遍,时间复杂度为O(K*N*N),高达10^10。

那么要怎么优化呢?如果要使用动态规划的话,K*N的子问题是无可避免的,我们只能去优化求解每个子问题的时间。

刚才我们每次求解子问题都是从i=1遍历到i=N,那么在这个遍历过程中,碎了的情况一开始肯定是最小的1次,逐步变大到N次。同时没碎的情况的次数肯定是从大到小的一个过程。在这样有规律的情况下,我们可以使用二分去优化。

优化后代码如下:

class Solution {

public:

int dp[105][10005] = { 0 };

int superEggDrop(int K, int N) {

if (K == 1) return N;

if (dp[K][N]) return dp[K][N];

for (int y = 1; y <= N; ++y) dp[1][y] = y;

for (int x = 2; x <= K; ++x)

{

for (int y = 1; y <= N; ++y)

{

int minNUM = y;

int i = 1;

int j = y;

while (i <= j)

{

int m = i + ((j - i) >> 1);

int broken = dp[x - 1][m - 1];

int enbroken = dp[x][y - m];

int temp = std::max(broken,enbroken) + 1;

if (temp < minNUM) minNUM = temp;

if (broken < enbroken) i = m + 1;

else j = m - 1;

}

dp[x][y] = minNUM;

}

}

return dp[K][N];

}

};


虽然通过了,但是在速度上只击败了6%的用户,说明还有更快的方法。

计算可知动态规划加二分优化的时间复杂度为O(K*N*logN)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,307评论 0 2
  • Fortran Best Practices ====================== .. highligh...
    boliecon阅读 182评论 0 1
  • 一年级语文上册生字表 生字表一(共400字) 啊(ā)爱(ài)安(ān)岸(àn)爸(bà)八(bā)巴(bā)...
    meychang阅读 2,752评论 0 6
  • 16年毕业的,如今已经一年了,路是越来越难走,因为自己之前没去好好努力,尝到如今的苦果。 初中时候,学习一直挺踏实...
    三月公子阅读 159评论 0 0
  • 突然觉得我长大,属于我的青春年华在悄悄的溜走。一直以来总觉得自己还小,可已经失去了少年的童真;觉得自己还小...
    柒号胆小鬼阅读 211评论 1 0