LeetCode 887. Super Egg Drop

本文探讨了一种优化算法,用于解决确定使鸡蛋不摔碎的最大楼层问题。通过动态规划方法,文章提出了一种新颖的解决方案,改变了传统求解最终操作数的方法,转而考虑在给定操作数下可确认的最大楼层数,极大地简化了解题过程。
摘要由CSDN通过智能技术生成

一、题目描述

You are given K eggs, and you have access to a building with N floors from 1 to N.

Each egg is identical in function, and if an egg breaks, you cannot drop it again.

You know that there exists a floor F with 0 <= F <= N such that any egg dropped at a floor higher than F will break, and any egg dropped at or below floor F will not break.

Each move, you may take an egg (if you have an unbroken one) and drop it from any floor X (with 1 <= X <= N).

Your goal is to know with certainty what the value of F is.

What is the minimum number of moves that you need to know with certainty what F is, regardless of the initial value of F?

Example 1:

Input: K = 1, N = 2
Output: 2
Explanation:
Drop the egg from floor 1. If it breaks, we know with certainty that F = 0.
Otherwise, drop the egg from floor 2. If it breaks, we know with certainty that F = 1.
If it didn’t break, then we know with certainty F = 2.
Hence, we needed 2 moves in the worst case to know what F is with certainty.

Example 2:

Input: K = 2, N = 6
Output: 3

Example 3:

Input: K = 3, N = 14
Output: 4

 


 

二、题目分析

  依题意,我们要求为了确定使鸡蛋从该层掉落也不会摔碎的最大的楼层数所需的最小操作数,无论该层数是多少(即在最坏的情况下至少要投下几次鸡蛋才能确定)。

  • 失败尝试:
      其实比较容易能想到的动态规划的方式是,在楼层数为 N 并且拥有 K 个鸡蛋时,记为条件 ( K , N ) ( K, N ) (K,N),我们在某一楼层 f 投下鸡蛋看它是否摔碎——此时以 f 层为分界线我们将楼层分为两部分: ( 0 , f − 1 ] ( 0, f-1 ] (0,f1] [ f , N ] [ f, N ] [f,N] ——若鸡蛋摔碎了,我们就在前半部分以条件 ( K − 1 , f − 1 ) ( K-1, f-1 ) (K1,f1) 找出所需楼层,否则在后半部分以条件 ( K , N − f ) ( K, N-f ) (K,Nf) 找出所需楼层,取这两者中找出所需楼层的操作数的最大值(最坏情况)作为从 f 层投下鸡蛋确认一次之后至少所需的操作数。于是我们令 f = 1 , 2 , . . . , N f = 1, 2, ..., N f=1,2,...,N ,求出所有的最坏情况,取它们之中的最小值即可找到答案。

      令 S ( K , N ) S( K, N ) S(K,N)表示使用 K 个鸡蛋确定 N 层楼的最终结果,则
             S ( K , N ) = m i n ( 1 + m a x ( S ( K − 1 , f − 1 ) , S ( K , N − f ) ) ) , f = 1 , 2 , . . . , N S( K, N )= min( 1 + max( S( K-1, f-1 ), S( K, N-f) ) ), f = 1, 2, ..., N S(K,N)=min(1+max(S(K1,f1),S(K,Nf))),f=1,2,...,N

      通过自底向上的动态规划来实现便可求得解。但不幸的是这样做复杂度太高了,为 O ( K N 2 ) O(KN^2) O(KN2),在测试的时候超时了,所以这样子是行不通的

  • 正解:
      在求解该题时,我们需要换个思路,不是求解最终的操作数,而是在给定操作数的情况下我们能确定到多少层楼,当该楼层数大于等于 N 的时候,我们就求得了答案。这样处理的话这道题就变得异常简洁明了,上面那些冗长的分析也并不需要了——令 F ( K , S ) F( K, S ) F(K,S) 表示使用 K 个鸡蛋在 S 步下能够确认的最大的楼层数,这些楼层应该这样 构成

       F ( K , S ) = F ( K − 1 , S − 1 ) + 1 + F ( K , S − 1 ) F( K, S ) = F( K-1, S-1 ) + 1 + F( K, S-1 ) F(K,S)=F(K1,S1)+1+F(K,S1)

    其中, 1 1 1 代表我们投下一次鸡蛋的层数,该层被确认了。而投下的鸡蛋会有两种情况:

    • 鸡蛋破碎,则我们少了一个鸡蛋,操作数也减一,但此时能够知道我们接下来应在 [ 1 , F ( K − 1 , S − 1 ) ] [ 1, F( K-1, S-1 ) ] [1,F(K1,S1)] 中确认目标楼层。
    • 鸡蛋没有破碎,只有操作数减一,此时能够知道我们接下来要在 [ F ( K , S − 1 ) , F ( K , S ) ] [ F( K, S-1 ), F( K, S ) ] [F(K,S1),F(K,S)] 中确认目标楼层。

    现在我们就能使用动态规划自底向上构建解了。

 


 

三、具体实现

  在通过鸡蛋数进行遍历时,可以改变顺序,变为从大到小遍历,便能使用一维数组来存储数据,节约空间。

class Solution
{
  public:
    int superEggDrop( int K, int N )
    {
        vector<int> floors( K + 1, 0 );
        int step = 0;

        for ( /**/; floors[K] < N; ++step ) {
            for ( int i = K; i >= 1; --i ) {
                // floors[i] means the number of the floors
                // which can be checked in 'step+1' moves using i eggs
                floors[i] = floors[i-1] + 1 + floors[i];
            }
        }

        return step;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值