對《丟雞蛋問題》的一點補充

2021-01-14 力扣加加

點擊藍色「力扣加加」關注我喲

加個「星標」,帶你揭開算法的神秘面紗!

去年的一年時間,我在群裡每天都會出題給大家做。但是就在 2020-03 開始,力扣也開展了每日一題活動。我突然覺得這個每日一題的必要性變得小了很多,並且逐漸減少了出題頻率。但是我還是不願意放棄大家一起集中進行交流學習的機會。於是我打算新開闢一個專題,這個專題一方面要和力扣官方的每日一題重合度低,另一方面要讓大家有參與的熱情。

於是【異議!】系列應運而生。它是個什麼東西呢?我相信大家一定在平時刷算法的過程中,一定遇到過「這解法怎麼想到的?」,「這解法不對吧?」的情況,並且可悲的是沒有人能夠回答你。來這裡,「力扣加加」 來回答你。我們會對大家提出的問題進行篩選,將有意義的問題開放出來給大家討論和學習。

本次給大家帶來的/是【異議!】系列「第二彈」。

原題地址:https://leetcode-cn.com/problems/super-egg-drop/

事情的起源

昨天有人在我的力扣題解下留言,問我《丟雞蛋問題》重製版來襲~》題解中為什麼第二種算法是加法而不是 min 什麼的。畢竟我的第一種算法可是 min(max(碎, 不碎)),為什麼第二種就是加法了呢?這個細節我在寫題解的時候漏掉了,我打算詳細給大家說一下。

題目描述

你將獲得 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

我當時的解法

我們這樣來思考這個問題。既然題目要求最少的扔的次數,假設有一個函數 f(k, i),他的功能是求出 k 個雞蛋,扔 i 次所能檢測的最高樓層。

我們只需要不斷進行發問:

」f 函數啊 f 函數,我扔一次可以麼?「, 也就是判斷 f(k, 1) >= N 的返回值」f 函數啊 f 函數,我扔兩次呢?「, 也就是判斷 f(k, 2) >= N 的返回值」f 函數啊 f 函數,我扔 m 次呢?「, 也就是判斷 f(k, m) >= N 的返回值

我們只需要返回第一個返回值為 true 的 m 即可。

想到這裡,我條件發射地想到了二分法。聰明的小朋友們,你們覺得二分可以麼?為什麼?歡迎評論區留言討論。

那麼這個神奇的 f 函數怎麼實現呢?其實很簡單。

摔碎的情況,可以檢測的最高樓層是f(m - 1, k - 1) + 1。因為碎了嘛,我們多檢測了摔碎的這一層。沒有摔碎的情況,可以檢測的最高樓層是f(m - 1, k)。因為沒有碎,也就是說我們啥都沒檢測出來(對能檢測的最高樓層無貢獻)。

我們來看下代碼:

class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        def f(m, k):
            if k == 0 or m == 0: return 0
            return f(m - 1, k - 1) + 1 +  f(m - 1, k)
        m = 0
        while f(m, K) < N:
            m += 1
        return m

上面的代碼可以 AC。我們來順手優化成迭代式。

class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        dp = [[0] * (K + 1) for _ in range(N + 1)]
        m = 0
        while dp[m][K] < N:
            m += 1
            for i in range(1, K + 1):
                dp[m][i] = dp[m - 1][i - 1] + 1 + dp[m - 1][i]
        return m

代碼

代碼支持:JavaSCript,Python

Python:

class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        dp = [[0] * (K + 1) for _ in range(N + 1)]
        m = 0
        while dp[m][K] < N:
            m += 1
            for i in range(1, K + 1):
                dp[m][i] = dp[m - 1][i - 1] + 1 + dp[m - 1][i]
        return m

JavaSCript:

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];
  }
  return m;
};

「複雜度分析」

為什麼是加法

在解法一種我提到了:「算法一的本質就是暴力地枚舉所有的可能樓層,然後比較最壞情況下的最少扔雞蛋次數」。而實際上解法二也是基於這個大前提,假設我們選擇一個樓層是 x。那麼在 x 層扔雞蛋會有兩種可能:

雞蛋碎了。說明目標樓層 F 就是本層或者比本層低,樓上的 N - x 層不需要檢測了,全部排除了。因此我們需要繼續探測樓下 x - 1 層,而我們剩下可以探測的最高樓層為 dp[k - 1][m - 1]。由於我們需要探測到具體的 F,因此我們需要使得 dp[k - 1][m - 1] >= x - 1。雞蛋沒碎。說明目標樓層 F 比本層高,樓下的 x - 1 不需要檢測了,全部排除了。因此我們需要繼續探測樓上 N - x 層,而我們剩下可以探測的最高樓層為 dp[k][m - 1]。由於我們需要探測到具體的 F,因此我們需要使得 dp[k][m - 1] >= N - x。❝

無論雞蛋碎還是不碎,我們都只需要檢測上面或者檢測下面,不需要同時檢測。

也就是說我需要找到一個樓層 x, 使得 x 同時滿足:

dp[k - 1][m - 1] >= x - 1

這樣能保證 100% 可以檢測出來目標樓層 F。實際上不管雞蛋碎不碎,可以檢測的樓層都是 「max(dp[k - 1][m - 1], x -1) + max(dp[k][m - 1], N -x) + 1」,由於 dp[k - 1][m - 1] >= x - 1,dp[k][m - 1] >= N - x,因此可以檢測的樓層就是 dp[k - 1][m - 1] + dp[k][m - 1] + 1。

這個我可能需要解釋一下。由於「選擇 x 開始扔之前已經確定了上面的兩個不等式是成立的了」,因此如果雞蛋沒碎,我們需要繼續往上檢測,下面是不需要檢測的,雖然下面是 x - 1,但是為了保證萬一碎的情況也有解,所以有 dp[k - 1][m - 1] >= x - 1,因此實際上可以確定的最大樓層是 dp[k][m - 1] + max(dp[k - 1][m - 1], x -1) + 1,也就是 dp[k][m - 1] + dp[k - 1][m - 1] + 1。雞蛋如果碎的情況也是一樣的分析邏輯。

大家對這道題還有任何問題,都可以留言告訴我!



1、力扣刷題插件

2、提前批算法工程師面試之路

3、動態規劃問題為什麼要畫表格?

4、《丟雞蛋問題》重製版來襲~

5、leetcode 刷500道題,筆試/面試穩嗎?談談算法的學習





相關焦點

  • 《丟雞蛋問題》重製版來襲~
    你知道存在樓層  F ,滿足  0 <= F <= N 任何從高於 F  的樓層落下的雞蛋都會碎,從  F  樓層或比它低的樓層落下的雞蛋都不會破。每一層樓丟雞蛋,都有兩種可能,碎或者不碎。由於是最壞的情況,因此我們需要模擬兩種情況,並取兩種情況中的扔次數的較大值(較大值就是最壞情況)。 然後我們從六種扔法中選擇最少次數的即可。
  • leetcode雞蛋掉落問題(egg drop)
    本來看算法4看得好好的,結果有一個作業提到了這個雞蛋掉落問題,實在是想不通啊otz。
  • 這位土澳大哥告訴你什麼叫一言不合就丟雞蛋!!
    再去看看他視頻的列表,還真的就是一些基本生活教程...突然看到「咋麼在澳大利亞做雞蛋」,感覺應該挺清奇的,還是看這個好了...那麼多個烤箱對著雞蛋一頓丟,哦不對,那麼多個雞蛋對著雞蛋一頓丟,哦不對...那麼多個雞蛋對著烤箱一頓丟!!臥槽這是啥意思啊!!
  • 兩個雞蛋的問題
    雙手各拿一個雞蛋,您用兩個雞蛋相互撞擊。兩個雞蛋一樣結實,撞擊的位置一樣。兩個雞蛋中的哪一個會被撞碎?是被撞的那個還是用來撞擊的那個?很多年前,美國《科學與發現》雜誌中提出了這個問題。這時,運動著的雞蛋內的液體物質在雞蛋撞擊的瞬間擠壓雞蛋殼,拱形物體承受這種壓力的能力相對於承受撞擊力要弱很多,所以雞蛋殼就會被撞碎。」 這個問題在列寧格勒一家發行量很大的報紙上被刊登時,得到了各種各樣的答案。答案中的一部分認為,被撞碎的肯定是用來撞擊的那個雞蛋;另一些答案則完全相反,認為用來撞擊的雞蛋會完好無缺。雙方似乎都拿出了有道理的論據。
  • 常吃魚肉與雞蛋,能為身體補充蛋白質?營養師:其實要學會這樣吃
    魚肉中的營養成分還很容易被身體消化和吸收,為身體補充能量。魚肉中的鎂元素,還能心血系統有很好的保養作用。雞蛋也是蛋白質含量較高的食物,雞蛋中的蛋白質還可以為身體補充能量,提高身體的抵抗能力。經常吃魚肉和蛋白質,還能為身體補充蛋白質,營養師也建議,其實魚肉和雞蛋要學會這樣吃。如何吃魚更有益補充蛋白質?
  • 15米高空丟雞蛋擊穿厚玻璃
    記者藉助奉賢消防支隊洪廟中隊的訓練場地進行了一個高空墜物試驗,準備的材料有50克左右的雞蛋和一塊3毫米厚的普通玻璃。記者站在距離地面15米高平臺上,向下垂直丟落雞蛋。雞蛋砸在玻璃上,直接將其擊碎。據一位高中物理老師介紹,一個物體從高處落下,落的高度越高,它到達地面的時候,速度就越快,所攜帶的能量和衝擊力也就越大。
  • 吃了這多年的雞蛋,你對它真的你都明白嗎?
    雞蛋要煮多久才可以吃?很明確的說,在5到10分鐘之間的雞蛋是可以吃了的,這個時候吃起來的口感不錯,大部分人都是選擇這個時間段。但是真的熟雞蛋,則是在10分鐘之後才算熟,這個時候吃起來有點幹硬,但這個時候的雞蛋是最安全的。
  • 大叔發明特殊快遞袋,雞蛋從兩層樓丟下來都不會破,年賺700萬
    大叔發明特殊快遞袋,雞蛋從兩層樓丟下來都不會破,年賺700萬現在生活上的很多東西都給我們帶來了很多便利,其中快遞業的出現與我們的生活越來越密切相關。然而,對那些易碎的物品需要更加小心。現在未免來看看該如何通過快遞安全運輸易碎物品。
  • 1個雞蛋含有340毫克膽固醇,血脂高,還能不能繼續吃雞蛋?
    前段時間,張文宏教授所說的增強免疫力要多吃雞蛋和牛奶,讓很多人對於雞蛋也有了新的認識,不喜歡吃雞蛋的人也開始改變自己,家中餐桌上也出現了雞蛋。雞蛋也是老百姓眼中有營養的食物,就像張文宏教授說的那樣,給大人孩子吃個雞蛋還能增強免疫力呢。
  • 為什麼美國人要冷藏雞蛋?
    這是一種附著在雞蛋上的具有潛在致命性的細菌。據疾控中心估計,沙門菌每年導致大約120萬人患病,450人死亡,不過這些病例並非都和雞蛋有關。 沙門菌可以穿過多孔的蛋殼,從外面的物質進入雞蛋。不過,在更少見的情況下,這種細菌也可以通過感染雞的卵巢,從體內感染雞蛋。
  • 為了增肌一天可以吃幾個雞蛋?應該吃幾個雞蛋?看營養師專業分析
    問了健身房的教練,建議他多吃一些雞蛋。可是他又擔心雞蛋吃多了對身體不好,專門來諮詢自己每天可以吃多少雞蛋。健美肯定需要增加肌肉量,要想增加肌肉,除了科學又艱苦單調的阻力訓練,還需要營養的配合。營養做得不好,肌肉量就上不去,甚至會掉肌肉。營養的第一個要求,就是攝入的總熱量要等於或者略多於消耗的熱量。
  • 每天吃雞蛋,對身體有什麼好處?哪些人不能多吃雞蛋?
    雞蛋是我們平常生活中,經常食用的一種食物,尤其是在早餐中,現在幾乎都會標配一個雞蛋。那麼每天吃雞蛋,對我們身體有什麼好處呢?哪些人不能多吃雞蛋?今天我們就來看看這些問題。一、食用雞蛋的好處1、補充優質蛋白雞蛋中最主要的成分之一是蛋白質。而且是優質蛋白,雞蛋中所含蛋白質的必需胺基酸的種類和模式和人體是最為接近的。簡單來說,雞蛋中的蛋白質最容易被人體所吸收。
  • 喝中藥能吃雞蛋嗎,喝中藥需注意哪些問題
    在日常生活當中,很多人生病會選擇通過中草藥來治療,因為中草藥的副作用比西藥要小一點,對身體傷害沒有這麼大,但是服用中草藥也是有很多細節要注意的,因為中草藥和許多東西是不能夠同時服用的,那麼在喝中草藥的時候應該注意哪些問題呢?服用中草藥的同時能不能吃雞蛋?
  • 關於孩子補充維生素D的問題:父母弄懂了,才不會做無用功
    但關於給孩子補充維生素D的問題,卻並非所有家長都清楚。比如需要補到什麼時候?什麼時候吃效果更好?如果已經在吃維生素AD,還需要維生素D嗎? 父母只有弄懂了,才不會做無用功,那就接著看吧。
  • 記者親歷「人造雞蛋」製造現場(下)
    你們以後造雞蛋的時候別忘了,一定要用開水,否則人家吃了,容易拉肚子的!」  然後,他又取過一隻碗,非常熟練地先後倒入食用明膠等其他原料,與少量水一起攪拌。在此過程中,何還講了一些人造蛋的秘訣:用雞湯或五香作料水制出的風味最佳(五香作料:八角、生薑、花椒等加水熬製而成);夏天氣溫高,要想人造蛋保鮮期長的話,苯甲酸鈉可以酌量多放一點……至於蛋黃的配製,記者發現,它只不過是在蛋清料的基礎上,加入了少量奶粉、檸檬黃色素。  而在成品製作中得用上模具。模具是石膏做的,巴掌大小,有圓形和橢圓形的兩個蛋坑,分別用來製作蛋黃和雞蛋成品。
  • 吃雞蛋的這幾個禁忌,請你堅決避免,第3條可能經常犯!
    雖然吃了好多年,但很多人對雞蛋了解不夠。殊不知,吃雞蛋時我們一定要注意這些問題:吃雞蛋注意事項1、不要吃生雞蛋或喝生雞蛋清有的人覺得食物加熱後會有營養流失,因此生雞蛋營養更豐富。另外,蛋黃富含大量鈣、磷、維生素 D 等人體必需營養素,是不折不扣的營養寶庫,吃雞蛋的時候可千萬別再把蛋黃丟了。小貼士:蛋黃的顏色深淺不一其實與它所含的色素有關,蛋黃顏色更深的雞蛋,其實並沒有多少營養上的優勢。
  • 每天1個雞蛋,膽固醇會超標?真正超標的,是這4種食物
    一天一雞蛋,相信這已經成為了不少人一種飲食習慣,雞蛋對於人體健康的好處,自然是不用多說的,給人體補充蛋白質的同時,雞蛋還富含多種人體所需維生素以及鈣、鎂等微量元素,是不可多得的營養補充食品。但對於雞蛋中蛋黃高膽固醇的問題,依然還是有不少人會詬病,會認為蛋黃中膽固醇含量過高,中老年人吃雞蛋不能吃蛋黃,否則膽固醇會超標,對健康不利。
  • 每天早上吃一個雞蛋,對身體有何益處?哪些人不能吃雞蛋?
    生活中,注重養生保健的人,會通過合理飲食改善身體,其中,包括每天早上吃一個雞蛋,堅持這樣做,可以改善身體,當然,也有一些人不會這樣做,忽略了吃早飯。那麼每天早上吃一個雞蛋的人,與不吃雞蛋的人相比,有哪些不同呢?吃雞蛋對身體有哪些益處呢?
  • 女人50歲後,每天吃一個雞蛋,會收穫到什麼?好處或會不請自來
    每天吃個雞蛋,現在很多家庭都是可以達標,對於每天一個雞蛋,有人也會產生疑問,害怕每天一個雞蛋,會給身體帶來不好的影響。也有人說,50歲以後的女性,應該每天吃一個雞蛋,會給身體帶來好處。說法各不相同,就不知道該相信哪一個了。究竟背後的答案是什麼,可以繼續的探究下去。
  • 買雞蛋時,是挑「大的」還是「小的」?養殖戶不小心說漏嘴,真的漲...
    其實我們在買雞蛋的時候都知道,不管在哪裡買雞蛋,都會有白皮的雞蛋,有紅皮的雞蛋,而且今天跟大家說的也是養雞場的大媽說漏了嘴我才知道,原來是這樣子來挑選雞蛋的,大家也學了以後就不要瞎買了。