重複番号を見つける- leetcode


挨拶仲間対!
あなたが全体のパンデミック状況にもかかわらず、うまくやっていると健康的な滞在している.
私は今日、私が学んだ問題にこの非常におもしろい/難しい解決について書きたかったです.

Finding the duplicate number within an array/list.


何かの前に、私はあなたを見てLeetcode problem statement .
そしてそれを解決しようとする.あなたがそれをすることができないならば、重要でありません.これは非常に奇妙な問題です.
与えられた
  • NUMのリストはN + 1整数を含んでいます.
  • NUM内の各numは範囲、1です.N (包含)
  • リストには1つだけ重複した番号があります.
  • 異なる解決策
  • リストを繰り返してソートし、2つの隣接するNUMが等しいかどうかを調べ、それらのNUMの1つを返します.
  • 別のリストに見たnumsを格納し、numが既に見られている場合はnumを返します.
  • また、問題へのフォローアップノート
  • 空間の複雑さはO ( 1 )定数空間でなければならない.
  • 時間の複雑さはo(n ^ 2)より小さくなければならない.
  • ホウ、大丈夫.フォローアップノートに一致するソリューションに.
    私は、バイナリの検索を解決策としてリストしていました.おそらく、一定の空間複雑さを持つ半分(SO O(log n))によって時間の複雑さを減らします.しかし、私はもう一つの解決に興味がありました、そして、それは少し挑戦的でした.どういうわけか、これを理解するのに1日かかった.

    nums = [2,6,4,1,3,1,5]
    Output - 1


    アイデアは2つのポインタを持つことですslow and fast . これらは次の要素へのインデックスとして現在の番号を使用してリストを移動します.そしていつものようにfast 前2歩進むslow . 反復は、重複する要素のためのサイクルを含むリンクリストを作成します.
    だから、この問題は、problem リンクリスト内のサイクルを見つける.
    新しい問題声明
    リンクリストを指定すると、サイクルの入口ノード/要素を見つけます.
    なぜサイクルの出発点を見つけるべきか?
    を読む.
    リンクリストの構築
    我々は今、繰り返しを介して番号のシーケンスを見つけるnums (上記で指定)とリンクリストを作成する.複製は同じ値を持って、このようにサイクルをつくる元の値にリンクします.それぞれの次の番号がどのように特定されているかの説明は、番号の隣にあります.[2,6,4,1,3,1,5]最初の要素から開始します.2 -> 4(nums[2]) -> 3(nums[4]) -> 1(nums[3]) -> 6(nums[1]) -> 5(nums[6]) -> 1(nums[5]) -> 6(nums[1]) -> 5(nums[6]) -> 1(nums[5]) -> ....そして、そのシーケンスはちょうど続きます.それはサイクルです.我々がそれを見るとき、我々はそれが好きです、現在、そのサイクルは始まります!
    オーケー、ファイン、まずこれからのリンクリストの視覚的な援助を構築しましょう.
    leetcodeに感謝します.
    Alt Text
    今のアプローチ
    重複要素は、番号のリスト内に存在するサイクルの入り口です.ちょっと待って?
    二段
  • Find if there's a loop - リストを繰り返している間、いくつかの点でslow and fast ポインタは同じノードを指しています.以来fast つのノードを前に移動します.fast and slow ループがある場合に限り、同じノードを指します.
  • Find the starting node of the cycle.
  • どうやってやるの?
    また、両方のノードを見つけたのでfast and slow ポイントは、私たちはちょうどそれを返すことができなかった?
    まあ.
    なぜ?
    交差点ノードは、この交差点ノードが必然的に複製要素/ノードであるというわけではないfast と追いついたslow またはfast and slow ポインタはランダムに会いました-これはちょうどリンクされたリストのサイクルがあるということを証明します.
    正確な複製要素を得るには、このループ/サイクルがどこで発生したかを見る必要があります.
    この原点を見つけるためにはslow リストの先頭へのポインタで、fast and slow 同じレートのポインタ、一度に1つ、そして、彼らが現在同じノードで会うとき、それはサイクル/ループの始まりです.
    いくつかの数学
    仮定するD = the number of steps/distance from the start of the linked list to the start of the cycle and K = the number of steps/distance from the start of the cycle to the intersection point ステップ1で判断した.以来slow 開始位置( 0 )、D ステップはD . The fast ポインタは交差点から続くので、D ステップは、NC(いくつかのサイクル数)−kであり、これはd=>に等しいnC - K = D.今、私たちは離れて、最後にこれをコード化する時間をクリア得た!
    class Solution:
        def findDuplicate(self, nums: List[int]) -> int:     
            slow = nums[0]
            fast = nums[0]
            while True:
                slow = nums[slow]
                fast = nums[nums[fast]]
                if slow == fast:
                    break    
            slow = nums[0]
            while slow != fast:
                slow = nums[slow]
                fast = nums[fast]   
            return fast
    
    あなたがこの解決を理解している闘争の間、立ち往生しているならば
  • Gauravセンのリンクリストのサイクルの開始を見つける上で素晴らしい.少なくとも2回見てください、そして、あなたは理解します.

  • Floyd's cycle detection algorithm ウィキペディア

  • This 本当にクールな解決策.

  • クールなyoutubersもこの問題と闘うことを理解する.
  • また、サイクル/ループがリンクされたリストに存在するかどうかを見つけることの間の違いを理解することは非常に重要です、そして、サイクルのエントリー/出発点がどこであるかについてわかっていてください.
  • またthis スタックオーバーフロー回答は、学習プロセス中の質問に多くの答えの源です.
  • もちろん、LeetCodeソリューションの説明を見てください.
  • 読書ありがとうございます.問題に対するこの解決策は、あなたが学習過程で立ち往生しているならば、私が理解していたタフなものでした.私を教えてください、多分私は助けることができる.