leetcode

扔鸡蛋(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 是多少。 示例 2: 输入:K = 2, N = 6 输出:3 示例 3: 输入:K = 3, N = 14 输出:4 提示: 1 <= K <= 100 1 <= N <= 10000   这题是一道经典的面试题,dabuladong那本书和leetcode官方都有很详细的讲解,我感觉这一题我理解得一知半解,估计多段时间可能会忘了,提醒下自己要记得重写一遍。 这题是动态规划,第一种定义动态规划数组的方法是达到K和N的状态需要的次数,这个次数呢是最坏的情况,意思就是达到这个次数后一定能找到那个楼层的。于是我们就可以知道这个最简单的办法就是以N为循环变量扫描一遍,对于每个N都计算最坏的情况,就是dp[K, N - N_i]和dp[K - 1, N_i - 1]的最大值,然后在所有最大值里面取最小的那个d**p(K,N)=1+1≤XNmin(max(d**p(K−1,X−1),d**p(K,NX)))

这里我们可以优化下,我们可以肯定知道这个循环有单调性,就是搜索难度是随楼层N的增加而增加的,于是就可以利用二分搜索。

\ /

\ /

\ /

我们就是要找dp中N – N_i和N_i相遇的那个点。

代码如下:


class Solution
{
public:
    int superEggDrop(int K, int N)
    {
        return dp(K, N);
    }

    int dp(int K, int N)
    {
        if (memo.find(N * 100 + K) == memo.end())
        {
            int ans;
            if (N == 0) ans = 0;
            else if (K == 1) ans = N;
            else
            {
                int lo = 1, hi = N;
                while (lo + 1 < hi)
                {
                    int x = (lo + hi) >> 1;
                    int t1 = dp(K - 1, x - 1);
                    int t2 = dp(K, N - x);

                    if (t1 < t2) lo = x;
                    else if (t1 > t2) hi = x;
                    else lo = hi = x;
                }

                ans = 1 + min(max(dp(K - 1, lo - 1), dp(K, N - lo)), max(dp(K - 1, hi - 1), dp(K, N - hi)));
            }
            memo[N * 100 + K] = ans;
        }
        return memo[N * 100 + K];
    }
private:
    unordered_map<int, int> memo;
};

 

我们还可以换个思路,就是dp数组记录的是T次尝试最多可以试的楼层,这样的话,我们就可以等当dp等于N的时候取T就行了。


class Solution
{
public:
    int cal(int K, int T)//此处的定义是给你K个鸡蛋,最多能尝试T次,最坏的情况下能测试的楼层数
    {
        if (T == 1 || K == 1)
            return T + 1;
        return cal(K - 1, T - 1) + cal(K, T - 1);
    }

    int superEggDrop(int K, int N)
    {
        int T = 1;
        while (cal(K, T) < N + 1)
            T++;
        return T;
    }
};

这个思路也可以二分搜索,不过我没写,这题我还没轮回贯通,之后还要重写下。

Leave a Reply

邮箱地址不会被公开。 必填项已用*标注