LeetCode50-高速電力アルゴリズムを学ぶための質問

この記事は個人のパブリックアカウントから作成されました:TechFlow、オリジナルは簡単ではありません、注意を求めてください


今日はLeetCode の31番目の記事です。LeetCodeの50番目の質問を見て、数値の力を見つけましょう。

タイトル

この質問の意味は、1つの文のみです。つまり、2つの数値xとnが与えられた場合、 バツ x ^ n

質問の観点から見ると、この質問は平凡で、基本的に特別なものではありません。しかし、そのノートを引き続き検討すると、問題が見つかります。ここで、xは浮動小数点数であり、その範囲は-100〜100です。nの範囲は32ビットintの範囲なので、ここに問題があります。

nが大きい場合、ループを使用して計算するため バツ x ^ n は、必ずタイムアウトになります。前にこの問題について説明しましたが、最速のコンピューティングC ++であっても、1秒あたりの操作数は約10の8乗にすぎません。32ビットのintは10の9乗です。Pythonの場合、この演算は遅くなるため、ループを使用して結果を取得することはできません。

高速パワー

この問題は複雑さを死に制限し、暴力的な方法からの結果を考えることができないため、新しいアルゴリズムを導入する必要があります。この問題のアルゴリズムは高速です。

高速電力アルゴリズムは、本質的にバイナリアルゴリズムの修正版です。これは、バイナリの完全な理解に基づいている必要があります。ある程度、複数ナップザック問題のバイナリ分割のソリューションに似ています。すべて整数を分割する必要がありますが、違いはバックパック問題の分割結果の累積演算であり、ここに累積乗算があります。

複数のナップザックの問題を見たことがない場合は、問題ではありません。最初から明らかにします。

高速電力アルゴリズムは理解しやすいですが、特に初心者の場合、それを読んだ後は忘れがちです。勉強していると理解できて、2日後に忘れてしまった、またはコードが書けないというのは正常です。したがって、私たちは基本的な問題から始め、それを操作の原理だけでなく根本から理解します。

最初の質問:高速パワー使用する理由何ですか?

ので、この質問は、当然のことながら、その答えに簡単で速いああ、そう私たちは、リサイクル使用のコンピューティングパワーはそれを行うことはありません。しかし、なぜ高速パワーが速いのですか?ループよりも速いのはなぜですか?

高速パワーのアルゴリズムを学習していなくても、この質問に答えることができます。答えるのも非常に簡単です。質問するのがそれほど簡単ではない量、簡単に解決できる量変換することで、複雑さを軽減します。それはナンセンスですが、それは多くのアルゴリズムの本質です。アルゴリズムは空から落ちるわけではなく、アルゴリズムを思いついた人が頭を掻いたりして出てきたわけでもありません。多くのアルゴリズムの中核となる原則は、変換および置換メソッドを使用して、特に便利ではない値を見つけることです。この方法は、数学だけでなく、アルゴリズムでも一般的に使用されます。

このコアを理解した後は、あとは簡単です。 バツ x ^ n 簡単に求めることはできません。良い方法がないので、どのくらい簡単に求めることができますか?変身するには?この考えに従って、私たちの目の前の世界はずっとはっきりしています。

もともと解決した バツ x ^ n の方法はループを通過させることであり、各ループはxで乗算され、結果はn回ループした後に得られます。このプロセスを観察すると、サイクルすると、各サイクルは実際にxのインデックス1の増加を表すことがわかりますつまり、直線的に増加しますが、もちろん遅くなります。では、何が速く成長しているのでしょうか?指数関数的成長は比較的速く、たとえば、私たちは倍増し、倍増してきましたが、それは非常に速いでしょう。誰かが過去にチェスを発明したと言って、指数関数的な成長についての有名な話があります。地元の王様はチェスをするのがとても好きなので、発明家を前に呼び、「この発明はあなたのために良いです。私はあなたに報酬を与えます。私がそれを与えることができる限り、あなたが望むものを言ってください。」と言いました。

男は私が欲しいのはほんの数メートルととてもシンプルだと言った。最初のグリッドに1メートル、2番目のグリッドに2メートル、3番目のグリッドに4メートルを配置します。各グリッドは前のグリッドの2倍の大きさです。田舎の貧しい人々にご飯をあげてください。

王はショックを受け、この人は不注意であると感じました。なぜそのような良い機会にはそのような報酬が必要なのですか。しかし、チェスの駒が合計886,64個あることは誰もが知っています。 2 65 1 2 ^ {65} -1 メートル。これは明らかに天文図であり、たとえ世界にそれほど多くのメートルがなくても、国は言うまでもありません。物語はその人の最後のエンディングについては触れていませんが、王をからかうためにハッキングされて死んだ可能性が非常に高いです。しかし、エンディングに関係なく、少なくとも1つの問題が説明されています。指数関数的成長は私たちの直感と一致せず、非常に急速に変化します。

したがって、インデックスを1つずつ増やすのではなく、指数関数的に増加させることができる場合、どのようにして指数関数的に増加させることができるでしょうか。これは非常にシンプルで、正方形です。

xを2乗して取得します バツ 2 x ^ 2 、もう一度二乗して取得します バツ 4 x ^ 4 二乗するたびに、ストーリーのチェス盤のように、インデックスが2倍になりました。したがって、インデックスを大きくするために必要なのは数回だけです。

指数関数的な成長率の問題を解決しましたが、新たな問題が発生しました。成長は非常に速いですが、2倍になると、nを取得できない場合があります

問題は、不可能を取得するための直接的な方法がしたかった、シンプルであるに参加聖歌。たとえば、n = 15の場合、15より小さい2の最大のべき乗を最初に見つけ、それが8であることを見つけます。だから最初に バツ 8 x ^ 8 、脇に置いた後、残り7、残り7、一緒に4を見つけて、脇に置いて、残り3になり、再び3を取りに来る...と続き、nこれは本質的にバイナリへの変換プロセスであるため、これまでのところ、nはこの方法で取得できなければなりません。

プロセス全体を図に描きました。下の図を見てみましょう。

最初に2のすべての累乗を計算し、次にすべてのxについて2の累乗を計算します。次に、nをバイナリに除算し、バイナリの対応する位置の値に1を乗算して結果を取得します。

一部の学生は、バイナリ演算とビット演算に慣れていない場合があります。理解しやすいように、2つのバージョンのコードを提供します。最初に、より簡単なコードを見てみましょう。

class Solution:
    def myPow(self, x: float, n: int) -> float:
        base = []
        # 标记n是否为负数
        flag = n < 0
        # 把n置为正数
        n = abs(n)
        base.append(x)
        # 我们算出所有的x^2^i
        for i in range(32):
            base.append(base[-1] * base[-1])
            
        ret = 1.0
        # 遍历32个二进制位
        # 如果i位为1,那么答案乘上base[i]
        for i in range(32):
            if ((1 << i) & n) > 0:
                ret *= base[i]
        # 如果n为负数返回1/ret
        return 1/ret if flag else ret

上記のコードでは、最初にそれぞれ計算しました バツ 2 x ^ {2 ^ i} 、次にnを2進数に変換した結果に従ってそれらを乗算します。もちろん、熟練した後は、手間を省くことができます。これらの2つのステップを組み合わせることができます。別のコードを見てみましょう。

class Solution:
    def myPow(self, x: float, n: int) -> float:
        base = []
        flag = n < 0
        n = abs(n)
        
        base = x    
        ret = 1.0
        # 我们在遍历二进制位的时候顺便求出x^2^i
        for i in range(32):
            if ((1 << i) & n) > 0:
                ret *= base
            # x^2^i = x^2^(i-1) * x^2^(i-1)
            base *= base
        
        return 1/ret if flag else ret

まとめ

この時点で、高速パワーについての説明は終わりました。個人的には比較的はっきりしているように感じます。アルゴリズムのコアはまだバイナリです。バイナリの概念をマスターしている場合、高速パワーアルゴリズムは少し意味があります。

疑問に思われるかもしれませんが、なぜternaryおよびquaternaryではなくbinaryを使用するのでしょうか?一つは、基礎となるバイナリコンピュータに基づいて二つの理由が、ありますが、私たちは、バイナリがシンプルであるため、良い材料は、三元を達成することができ見つからないハイとローの状態だけで罰金を表しもたらし、オンとオフの論理ゲートが、 3つの状態を実現するためにどのような材料が使用されますか?2番目の理由は、それが必要ではないことです。Multi-aryは確かに高速ですが、非常に制限されているため、必要ありません。

私は冗談を恐れていません。最初に始めたとき、私はいつも上記の愚かな方法を使いました。そして、解決策を見て、私はこの愚かな方法で速い力を書く人を見つけていません。しかし、コードが愚かであるかどうかは問題はなく、実行でき、ACであり、理解できます。最初から愚かなコードを書いてもかまいません。改善を続けている限り、自然に次第に良くなっていきます。

今日の記事はそれだけです。もし何かやりがいを感じた場合は、フォローまたは再投稿しください。あなたの努力は私にとって非常に重要です。

ここに画像の説明を挿入

117件の元の記事を公開 61のような 10,000以上の訪問

おすすめ

転載: blog.csdn.net/TechFlow/article/details/105644945