友人の皆さん、また会いましょう。今回は、LeetCode の 141 番目の単一リンク リスト OJ 問題について説明します。読んでインスピレーションが湧いた場合は、三部作を残してください。ご多幸をお祈りします。すべての願いが叶います!
データ構造とアルゴリズム コラム:データ構造とアルゴリズム
個人ホームページ : stackY、
C言語コラム: C言語:エントリーからマスターまで
LeetCode--141. リングのリンク リスト: https://leetcode.cn/problems/linked-list-cycle/description/
1. トピックの紹介
リンクリストの先頭ノードheadを与え、リンクリストにリングがあるかどうかを判定します。
リンクされたリスト内に次のポインタを継続的に追跡することによって再度到達できるノードがある場合、リンクされたリスト内にサイクルが存在します。指定されたリンク リスト内のリングを表すために、評価システムは内部で整数 pos を使用して、リンク リストの末尾がリンク リストに接続される位置を示します (インデックスは 0 から始まります)。注: pos はパラメータとして渡されません。リンクリストの実態を特定するためだけに。
リンクされたリストに循環がある場合は true を返します。それ以外の場合は false を返します。
2. デモ例
3. 解決策のアイデア
ここで、循環リンクリストの判定に最も基本的な方法を使用すると、さらに面倒になり、方法もそれほど多くありませんので、ここでは、まだ高速ポインタとスローポインタの方法である方法を提供します。に精通している:
高速ポインタと低速ポインタを設定できます。リングがある場合、高速ポインタの速度は常に低速ポインタの 2 倍であるため、高速ポインタと低速ポインタはリング内で一致する必要があります。そのため、高速ポインタがリングの低速ポインタに追いつくことができます。最初にこの比較的単純な方法を使用しましょう。後で検証できます。
コードデモ:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ bool hasCycle(struct ListNode *head) { //设置快慢指针 struct ListNode* slow = head; struct ListNode* fast = head; while(fast && fast->next) { //快指针一次走两步 fast = fast->next->next; //慢指针一次走一步 slow = slow->next; //如果在环中相遇就带环 if(fast == slow) { return true; } } //如果整个链表都走完了还是没有相遇则不带环 return false; }
この方法は簡単そうに見えますが、どうやって証明するのでしょうか? 見下ろしてみましょう:
4. 面接の質問を拡張する
1. リングがあり、高速ポインタが一度に 1 ステップずつ移動し、低速ポインタが一度に 2 ステップ移動すると仮定します。高速ポインタは低速ポインタに追いつきますか?
速いポインタの速度は遅いポインタの2倍であるため、速いポインタはリングに進み、遅いポインタは後ろからリングに入ります。速いポインタと遅いポインタの間の距離をNとします。スロー ポインター (遅い) がリングに入り、速いポインター (速い) がスロー ポインター (遅い) を追いかけ始めます。速いポインターは一度に 2 歩進み、遅いポインターは一度に 1 歩進みます。すると、それらの距離は長くなります。歩数に応じて徐々に 1 ずつ減少します。これは許容値が -1 の算術数列であり、歩いている限り、十分な歩数がある場合、高速ポインタは確実に低速ポインタと一致します。
したがって、遅いポインタは 1 ステップずつ、速いポインタは 2 ステップずつ実行され、必ず追いつきます。
2. ループがあると仮定して、高速ポインタが任意のステップ数を実行し、低速ポインタが 1 ステップ実行する場合、高速ポインタは低速ポインタに追いつくことができますか?
ここでは、高速ポインタが一度に 3 ステップずつ移動し、低速ポインタが一度に 1 ステップずつ移動すると仮定します。
速いポインタの速度は遅いポインタの 3 倍であるため、速いポインタがリングに進み、遅いポインタが後からリングに入る場合、速いポインタと遅いポインタの間の距離を N とします。スロー ポインター (遅い) がリングに入り、速いポインター (速い) がスロー ポインター (遅い) を追いかけ始めます。速いポインターは一度に 3 歩ずつ歩き、遅いポインターは一度に 1 歩ずつ歩きます。その後、それらの距離は歩く歩数に応じて 2 ずつ減少します。これは、許容値が -2 の算術数列です。このとき、それらの間の距離を計算する必要があります。
ステップ数の増加に応じて、スピード ポインターの距離が -1 に変化します。これは、次のラウンドの追跡が開始されることを意味します。次のラウンドの追跡は、次の 2 つの状況に分けられます。
1. リングの円周をCとすると、速いポインタと遅いポインタの距離はC-1となり、このときC-1が奇数だと絶対に追いつきません。
2. リングの円周をCとすると、速いポインタと遅いポインタの距離はC-1となり、このときC-1が偶数であれば追いつくことができます。
要約:
1. 高速ポインタは 1 ステップずつ移動し、低速ポインタは 2 ステップずつ移動します。高速ポインタは必ず低速ポインタに追いつきます。
2. 高速ポインタが任意のステップ数を実行し、低速ポインタが 1 ステップ実行する場合、高速ポインタが低速ポインタに追いつけない可能性があります。
友人の皆さん、楽しい時間はいつも短命です。この号での共有はこれで終わりです。読み終わったら、貴重な 3 部作を忘れないでください。ご支援ありがとうございました!