スピードポインター
記事ディレクトリ
一般的なパターン
リンクリストに関連して、リンクリストにループがあるかどうかなどを確認します。
最初の循環リンクリスト
アイデア:
リンクリストが循環リンクリストの場合、2つのポインタを定義できます。1つは一度に2つのノードを前方に移動し、もう1つは一度に1つのノードを前方に移動します。これは、陸上競技と同じです。2人のアスリートがまっすぐ走る場合、速いアスリートと遅いアスリートは開始点で同じ位置にありますが、速いアスリートは最初に終わりに到達し、その間に2人のアスリートは到達しません。会いましょう。また、円を描くように走ると(メーター数に制限がないと仮定して)、速いアスリートが遅いアスリートを1周上回ったときに出会うので、現時点では循環リンクリストです。
亀とうさぎとの違い:
速いポインターと遅いポインターの2つのポインターの速度について:亀とウサギのレースとは異なり、亀とウサギのレースは連続性の問題です.2つの間の速度差がいくらあっても、次のように推測できます:トラックの長さがsであると仮定すると、 v_fは高速の値を表し、v_sは低速の値を表します(2つの初期位置が同じであると仮定)。次のようになります。(v_f-v_s)t = s;この方法で計算されたtは、2つが初めて出会うときです。この質問の違いは次のとおりです。リンクリストの場合、これは離散値です。リングにn個のノードがあると想定します。また、高速ポインタと低速ポインタがそれぞれv_fとv_sであると想定します。満たす場合(同じ初期位置を想定) 、(v_f-v_s)k = n;-この時点で、v_f、v_sは正の整数、kはサイクル数、nはノード数です。k= n /(v_f-v_s)kを整数にする場合は、 2つの間の速度差が必要であり、nで割り切れる必要があることがわかります。注:これは初めての場合であり、v_f-v_sがnの整数倍である可能性もあります。
コード:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null)
return false;
ListNode p=head;
ListNode q=head;
while(p!=null&&q!=null)
{
p=p.next;
if(q.next==null)
return false;
q=q.next.next;
if(p.equals(q))
{
return true;
}
}
return false;
}
}
2番目の循環リンクリスト
アイデア:
図に示すように、非リングにノード
があり、リングにbノードがあるとし
ます。
fast走的节点数=2*slow走的节点数\\
fast走的节点数-slow走的节点数=nb(多走了n圈)
第一次相遇时slow走的节点数为nb
一个节点走a+nb步一定会在入口处
slow在第一次相遇后再走a步即可
可以第一次相遇后,设置一个指针从头开始,以slow的速度,两者相遇时即为入口
コード:
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null)
return null;
ListNode p=head;
ListNode q=head;
if(head.next==null)
{
return null;
}
while(p!=null&&q!=null)
{
p=p.next;
if(q.next==null)
return null;
q=q.next.next;
if(p.equals(q))
{
q=head;
while(p!=null&&q!=null)
{
if(p.equals(q))
{
return p;
}
q=q.next;
p=p.next;
}
}
}
return null;
}
}
3番目のリンクリストの中央ノード
アイデア:
高速ポインタは一度に2つのノードを通過し、
低速ポインタは一度に1つのノードを通過します。
高速ポインタが最後に到達すると、低速ポインタは中央の位置に到達します。
コード:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(true)
{
if(fast.next==null)
{
return slow;
}
if(fast.next.next==null)
{
slow=slow.next;
return slow;
}
else {
fast=fast.next.next;
slow=slow.next;
}
}
}
}
4番目の方法は、リンクリストの下部からn番目のノードを削除することです。
アイデア:
高速ポインタ
は最初にnノードに移動し、次に高速ポインタと低速ポインタは一度に1ノード下に移動します
。高速ポインタが最後に
到達すると、低速ポインタが到達する位置は下からn番目のノードになります。
コード:
public static ListNode deleteNode(ListNode head,int n) {
ListNode p=head;
ListNode q=head;
for(int i=0;i<n-1;i++)
{
p=p.next;
}
while(true)
{
if(p.next.next==null)
{
q.next=q.next.next;
return head;
}
p=p.next;
q=q.next;
}
}