[没事儿刷两道-Leetcode.887] 鸡蛋掉落-动态规划

题目

你将获得 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 是多少。
提示
1 <= K <= 100
1 <= N <= 10000

题解

看到题目,第一时间想到了用二分查找的思路来解题,碎了往下走,没有碎往上走。但是看题目会发现还有一个数据K没有利用上,扔鸡蛋还会受到鸡蛋数量的约束,比如有1个鸡蛋,7层楼,二分查找从第四层开始扔,如果鸡蛋碎了,就无法继续进行测试了。因此仅仅使用二分查找思路是不可取的。
此题采用动态规划的方法,同样的首先分析【状态】,即你目前有的鸡蛋数量,和所在的楼层数,其次分析【选择】,即下一次在几楼扔。

设我们在第i层扔出了鸡蛋,根据题意
如果鸡蛋碎了:则k--,下一次扔的楼层应该在[1,i-1]之间
如果鸡蛋没碎:则k不变,下一次扔的楼层在[i+1,N]之间,
因此我们在i层有k个鸡蛋必须移动的部署为ans_i = max(dp(k-1,i-1),dp(k,i+1)) + 1
N层楼需要的最少步数为min(ans_1,ans_2,...,ans_n),代码描述为:

int dp(int k,int n){
    int ans;
    for(int i = 0;i < n;i++){
        ans = min(ans,max(dp(k-1,i-1),dp(k,n-i) + 1);
    }
    return ans;
}

base case :

    if(k == 1) return n;
    if(n == 0) return 0;
代码
class Solution {
public:
    int superEggDrop(int K, int N) {
        if(K == 0 || N == 0) return 0;
        if(K == 1) return N;
        if(N == 1) return 1;
        int minDrop = N + 1;
        for(int x = 1; x <= N; x ++){
            minDrop = min(minDrop, max(superEggDrop(K, N-x), superEggDrop(K-1, x-1)) + 1);
        }
        return minDrop;
    }
};

此算法时间复杂度为指数级,因此我们考虑采用带有备忘录的动态规划算法来进行优化,具体操作为用一个数组存放K,N状态下需要的步数,每次dp时先查询该状态是否已经存在,如过存在则直接返回该值值,由于题目中1<=k<=100,我们可以用N * 100 + k来表示K,N状态的序号,每次返回前将步书保存在unordered_map(内部为hash表比map的查询速度快)中。

优化1:
class Solution {
    unordered_map<int,int> t;
public:
    int superEggDrop(int K, int N) {
        if(K == 0 || N == 0) return 0;
        if(K == 1) return N;
        if(N == 1) return 1;
        if(t.find(N*100+K) == t.end()){
            int ans = N + 1;
            for(int x = 1; x <= N; x ++){
                ans = min(ans, max(superEggDrop(K, N-x), superEggDrop(K-1, x-1)) + 1);
            }
            t[N*100+K] = ans;
        }
        return t[N*100+K];
    }
};

然而通过备忘录之后的时间复杂度仍为O(KNN),仍然无法满足,此刻回忆我们最初想到的二分查找思路,我们通过二分查找的思路,可以将时间复杂度降至O(KNlogN),具体操作为:
先前我们的搜索方式都是线性搜索,观察dp(K-1,x-1)和dp(K,N-x),当K一定时随着x的增大前者单调递增,后者单调递减。因此dp(K,N) = MIN(MAX(dp(K-1,x-1),dp(K,N-x)) + 1)可以看作求两个函数交点,这个过程可以通过二分查找来进行优化

class Solution {
    unordered_map<int,int> t;
public:
    int superEggDrop(int K, int N) {
        if(K == 0 || N == 0) return 0;
        if(K == 1) return N;
        if(N == 1) return 1;
        if(t.find(N*100+K) == t.end()){
            int ans = N + 1;
            int l = 1,h = N;
            while(l <= h){
                int mid = (l + h) / 2;
                int broken = superEggDrop(K-1,mid-1);
                int not_broken = superEggDrop(K,N-mid);
                if(broken > not_broken){
                    h = mid - 1;
                    ans = min(ans,broken + 1);
                }
                else{
                    l = mid + 1;
                    ans = min(ans, not_broken + 1);
                }
            }
            t[N*100+K] = ans;
        }
        return t[N*100+K];
    }
};

此时算法搜索的时间复杂度已经优化为O(logN),总体时间复杂度优化为O(KNlogN),可满足题目要求

关于动态规划,推荐几个学习内容:

背包九讲
动态规划套路详解
labuladong的算法小抄

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

推荐阅读更多精彩内容