その他の話:古典的なアルゴリズムの卵落下問題

0まえがき

卵が落ちる問題は、古典的なアルゴリズムの問​​題と見なすことができ、リートコードにも含まれています。これは、私が収集した数少ない問題の1つです。確かに興味深い問題です。LiYongle先生もビデオで話をしました。この問題。

たまたま、今日は体調が悪く、風邪をひいて、新しいことを学ぶ気力がなかったので、古いものを拾って少し見直しました。

1.はじめに

まず、古典的なアルゴリズムの問​​題の説明を見てみましょう。

  • 手にK個の卵があり、F階がクリティカルなN階建ての建物があります。F階以下から落ちても壊れませんが、逆に卵になります。 F階より高い上層階から落下すると卵が割れるので、臨界層Fを確実に見つけるには少なくとも数回の実験が必要です。

対応するリートコードのタイトルは次のように説明されています。

2.アルゴリズムのアイデア

実際、このトピックで最初に得た反応は、最適なソリューションを直接与えることができるかどうかでした。結果はより良いものでした。その後、いくつかのソリューションを読んだ後、これは動的計画法の古典的な問題であることがわかりました。少なくともアルゴリズムは解くことができます。

明らかに、卵が1つしかない場合は、いくつかのフロアがあり、重要なレイヤーFを見つけるために、いくつかの実験を行う必要があります。フロアが1つしかない場合は、手元にある卵の数に関係なく、必要な実験の数は1回です。

次に、次のように漸化式をすばやく与えることができます。

dp[k][n] = min(1+max(dp[k-1][i-1], dp[k][n-i]) for i in range(1, n+1))

つまり、i階から落下する各操作の状況を調査するために、壊れていない場合は2階の9階のみを検査する必要があり、逆に壊れている場合はkのみを検査する必要があります。 -1個の卵この場合、クリティカルフロアを確実に取得するには、i-1フロアにいくつの実験が必要です。

3.コードの実装

Pythonコードの実装は次のとおりです。

class Solution:
    def superEggDrop(self, K: int, N: int) -> int:
        dp = [[0 for i in range(N+1)] for _ in range(K+1)]
        for k in range(1, K+1):
            for n in range(1, N+1):
                if k == 1:
                    dp[k][n] = n
                elif n == 1:
                    dp[k][n] = 1
                else:
                    dp[k][n] = min(1+max(dp[k-1][i-1], dp[k][n-i]) for i in range(1, n+1))
        return dp[K][N]

コードを送信した後、いくつかの例をテストしたところ、すべて正しかったのですが、LeetCodeでのコード評価中にタイムアウトエラーが発生しました。結局、上記のコードの時間計算量はO(N 3)O(N ^ 3)です。O N3桁違い。

4.アルゴリズムの最適化

もう1つのより洗練されたコード実装は、leetcodeで提供されます。

まず第一に、彼の考えは、先に述べたように、明確なKとNの状況ごとに具体的な答えを明示的に計算することではなく、K個の卵がある場合に最大でn回の実験を行うという問題を解決することです。しきい値フロアを下回っているフロアの数を決定します

次のように漸化式を与えることもできます。

dp[k][n] = dp[k-1][n-1] + 1 + dp[k][n-1]

その中で、kは前の定義と一致しています。つまりk個の卵があり、nは最大でn個の操作があるdp[k][n]こと意味します。つまり、k個の卵がある場合、しきい値フロアより下のフロア数を保証できます。 n回の操作。

5.コードの実装

Pythonコードは次のとおりです。

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

        for n in range(1, N+1):
            for k in range(1, K+1):
                if k == 1:
                    dp[k][n] = n
                else:
                    dp[k][n] = dp[k-1][n-1] + 1 + dp[k][n-1]
                if dp[k][n] >= N:
                    return n
        return -1

前のO(N 3)O(N ^ 3)からのコードの複雑度O N3O(N 2)に縮退O(N ^ 2)O N2、コードを送信した後、leetcodeでスムーズに渡されます。

6.まとめ

要約すると、基本的にこの質問について説明しました。ただし、現在の実行効率はまだ最適ではありません。LeetCodeには、時間がかかり、さらに最適化できる改善されたソリューションがいくつかありますが、考え方は同じであり、アルゴリズム全体の複雑さもO(N 2)O(N ^ 2)O N2ですが、実装の詳細は同じではありません。よりわかりやすく説明するために、上記の記述方法を使用します。これはより説明的です。

読者がより効率的なコードに興味がある場合は、LeetCodeにアクセスして確認できます。

おすすめ

転載: blog.csdn.net/codename_cys/article/details/111085961