887.super-egg-drop.md 5.1 KB
Newer Older
L
luzhipeng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211

## 题目地址
https://leetcode.com/problems/super-egg-drop/description/

## 题目描述

```
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
 

Note:

1 <= K <= 100
1 <= N <= 10000


```

## 思路

这是一道典型的动态规划题目,但是又和一般的动态规划不一样。

拿题目给的例子为例,两个鸡蛋,六层楼,我们最少扔几次?

![887.super-egg-drop-1](../assets/problems/887.super-egg-drop-1.png)

一个符合直觉的做法是,建立dp[i][j], 代表i个鸡蛋,j层楼最少扔几次,然后我们取dp[K][N]即可。

代码大概这样的:

```js
 const dp = Array(K + 1);
    dp[0] = Array(N + 1).fill(0);
    for (let i = 1; i < K + 1; i++) {
      dp[i] = [0];
      for (let j = 1; j < N + 1; j++) {
        // 只有一个鸡蛋
        if (i === 1) {
          dp[i][j] = j;
          continue;
        }
        // 只有一层楼
        if (j === 1) {
          dp[i][j] = 1;
          continue;
        }

        // 每一层我们都模拟一遍
        const all = [];
        for (let k = 1; k < j + 1; k++) {
          const brokenCount = dp[i - 1][k - 1]; // 如果碎了
          const notBrokenCount = dp[i][j - k]; // 如果没碎
          all.push(Math.max(brokenCount, notBrokenCount)); // 最坏的可能
        }
        dp[i][j] = Math.min(...all) + 1; // 最坏的集合中我们取最好的情况
      }
    }

    return dp[K][N];
```

果不其然,当我提交的时候,超时了。 这个的时复杂度是很高的,可以看到,我们内层暴力的求解所有可能,然后
取最好的,这个过程非常耗时,大概是O(N^2 * K).

然后我看了一位leetcode[网友](https://leetcode.com/lee215/)的回答,
他的想法是`dp[M][K]means that, given K eggs and M moves,what is the maximum number of floor that we can check.`

我们按照他的思路重新建模:

![887.super-egg-drop-2](../assets/problems/887.super-egg-drop-2.png)

可以看到右下角的部分根本就不需要计算,从而节省很多时间
## 关键点解析

- dp建模思路要发生变化, 即
`dp[M][K]means that, given K eggs and M moves,what is the maximum number of floor that we can check.`


## 代码

```js

/*
 * @lc app=leetcode id=887 lang=javascript
 *
 * [887] Super Egg Drop
 *
 * https://leetcode.com/problems/super-egg-drop/description/
 *
 * algorithms
 * Hard (24.64%)
 * Total Accepted:    6.2K
 * Total Submissions: 24.9K
 * Testcase Example:  '1\n2'
 *
 * 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
 *
 *
 *
 *
 * Note:
 *
 *
 * 1 <= K <= 100
 * 1 <= N <= 10000
 *
 *
 *
 *
 *
 */
/**
 * @param {number} K
 * @param {number} N
 * @return {number}
 */
var superEggDrop = function(K, N) {
  // 不选择dp[K][M]的原因是dp[M][K]可以简化操作
  const dp = Array(N + 1).fill(0).map(_ => Array(K + 1).fill(0))
  
  let m = 0;
  while (dp[m][K] < N) {
      m++;
      for (let k = 1; k <= K; ++k)
          dp[m][k] = dp[m - 1][k - 1] + 1 + dp[m - 1][k];
  }
  console.log(dp);
  return m;
};
```