ニューヨーク大学 LeetCode142 リンク リスト サイクル II

LeetCode142 リンク リスト サイクル II


作成者: Stefan Su
作成時間: 2022-10-29 02:40:13
場所:米国ニューヨーク州ニューヨーク市

説明Medium

headリンクされたリストの を指定すると、サイクルが始まるノードを返します。サイクルがない場合はリターンしますnull

ポインタを継続的にたどることによって再度到達できるノードがリスト内にある場合、リンクされたリスト内にサイクルが存在しますnext内部的には、postail のポインタが接続されているノードのインデックスを示すために使用されますnext( 0 からインデックス付き)。-1サイクルが無い場合です。pos はパラメータとして渡されないことに注意してください

リンクされたリストは変更しないでください。

例1

ここに画像の説明を挿入

Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle in the linked list, where tail connects to the second node.
例 2

ここに画像の説明を挿入

Input: head = [1,2], pos = 0
Output: tail connects to node index 0
Explanation: There is a cycle in the linked list, where tail connects to the first node.
例 3

ここに画像の説明を挿入

Input: head = [1], pos = -1
Output: no cycle
Explanation: There is no cycle in the linked list.
制約する
  • リスト内のノードの数は[0, 104]の範囲内です。
  • -105 <= Node.val <= 105
  • pos-1またはリンクリスト内の有効なインデックスです。

分析

2点

  1. リンクされたリストが循環的かどうかを確認する
  2. リングがある場合、そのリングの入り口を見つける方法

詳細

  1. リンクされたリストが循環的かどうかを確認する

    2 ポインター メソッドを使用して、fastおよびslowポインターをそれぞれ定義できます。headポインタはノードから開始してfast一度に 2 つのノードを移動し、slowポインタは一度に 1 つのノードを移動します。fastslowポインタが途中で交わる場合は、リンクされたリストにリングがあることを意味します。

    なぜfast2 つのノードに移動しslow、1 つのノードに移動し、リングがある場合、永遠にずらされるのではなく、必ずリング内で合流するのでしょうか?

    まず第一に、最初のポイント:ポインタfastは最初にリングに入らなければなりません。fastポインタとポインタが出会う場合slow、それらはリング内で出会う必要がありますが、それは疑いの余地がありません

    それでは、なぜポインタとポインタが一致する必要があるのか​​見てみましょうfastslow

    リングを描画して、任意のノードでfastポインターがポインターに追いつき始めるようにすることができますslow
    fastそしてslowそれぞれが一歩踏み出しfastslow出会う

    fast二歩歩いてslow一歩踏み出すからである。実際、 と比較するとslowfastは に近いノードなのでslowfastと重ねることができるはずですslow

  2. リングがある場合、そのリングの入り口を見つける方法

    この時点で、リンクリストにリングがあるかどうかが判断できるので、次のステップはこのリングのエントリを見つけることです。

    ヘッドノードからリングエントリノードまでのノード数が であるとしますxfastリング入口ノードからポインタが出会うノードまでのノード数は でslowあるyエンカウントノードからリングエントリノードまでのノード数は ですz写真が示すように:

    ここに画像の説明を挿入

    次に、それらが出会うとき: ポインタによって渡されるノードの数はslow: x + y、ポインタによって渡されるノードの数fast: x + y + n (y + z)、ここで、はポインタと出会うまでのリング内の円の後のポインタnであり円内のノードの数 A です。fastnslow(y+z)

    fastポインターは一度に 2 つのノードを移動し、slowポインターは一度に 1 つのノードを移動するため、fastポインターが通過するノードの数は、ポインターが通過するノードの数の 2 倍に等しくなりますslow

    (x + y) * 2 = x + y + n(y + z)

    両側から 1 つを削除します(x+y)x + y = n (y + z)

    リングへの入口を見つける必要があるため、はヘッド ノードからリング入口ノードまでの距離を表すxため、必須です。x

    それで、 を求めてxx左側に単独で置いてください: x = n (y + z) - y

    (y+z)次に、 fromを考え出しますn(y+z)式を整理すると、次の式になります。ポインターに出会うまでにポインターは少なくとももうx = (n - 1) (y + z) + z1 周移動する必要があるため、ここでは n が 1 以上である必要があることに注意してくださいfastslow

    この式は何を示しているのでしょうか?

    例として、n が 1 の場合を考えてみましょう。これは、高速ポインタがリング内で回転した後、低速ポインタに遭遇することを意味します。

    n が 1 の場合、式は次のように解決されますx = z

    これは、ヘッドノードからポインタが設定され、エンカウントノードからもポインタが設定されることを意味する。これら 2 つのポインタは一度に 1 つのノードにしか移動しないため、これら 2 つのポインタが出会うと、それがリング エントリのノードになります

    つまり、遭遇ノードでポインタを定義し、ヘッド ノードにindex1ポインタを設定します。index2

    同時に 1 ノードずつ移動し、それらが出会う場所がリングの入り口のノードになりますindex1index2

    では、n が 1 より大きい場合、つまり、リング内を n 周した後でfastポインターがポインターに遭遇した場合はどうなるでしょうか。slow

    実際、この状況は n が 1 の場合と同じであり、この方法でリングの入口ノードを見つけることができますが、ポインタはリング内でさらに多くの回数index1回転し、その後 に遭遇します。集合点は依然として入口ノードです。リングの。(n-1)index2

解決

  • 2つのポインターのバージョン
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    
    
    public ListNode detectCycle(ListNode head) {
    
    
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
    
    
            fast = fast.next.next;
            slow = slow.next;

            if (slow == fast) {
    
    
                ListNode index_1 = fast;
                ListNode index_2 = head;
                while (index_1 != index_2) {
    
    
                    index_1 = index_1.next;
                    index_2 = index_2.next;
                }
                return index_1;
            }
        }
        return null;
    }
}

LeetCode142 を解決する際に、このブログがインスピレーションになれば幸いです。ご質問がございましたら、以下にコメントしてください。

おすすめ

転載: blog.csdn.net/Moses_SU/article/details/127586364