(Java データ構造) リンク リストの質問

循環連結リスト

リンクされたリストにサイクルがあるかどうかを判断する

leetcode
141. 环形链表

ここに画像の説明を挿入

追いかけて会う問題と同様に、高速ポインターと低速ポインターを定義します.リングがなければ、高速ポインターはゼロになり、リングがあれば、高速ポインターと低速ポインターはリング内で確実に出会います.
スロー ポインターが一度に 1 ステップ移動する場合、ファースト ポインターは一度に 2 ステップ移動する必要がありますか? それとも3歩?4段?

ファスト ポインターが 2 歩歩き、スロー ポインターが 1 歩歩くたびに、最悪の場合、スロー ポインターがリングに入ったときに、ファスト ポインターはスロー ポインターよりリング距離を 1 つ多く歩きます。スロー ポインターよりも 1 歩多く歩くので、スロー ポインターが円に到達する前に、ファスト ポインターがスロー ポインターに追いつくことができます。ここに画像の説明を挿入

リング内に 2 つのノードしかない場合、高速ポインターが毎回 3 ステップ移動し、低速ポインターが毎回 1 ステップ移動する場合、高速ポインターと低速ポインターは決して一致しません。
ここに画像の説明を挿入

したがって、一度に 2 つのステップを実行するように高速ポインターを設定し、一度に 1 つのステップを実行するように低速ポインターを設定すると、2 つのポインターはリング内で確実に一致します。遅いポインターが 1 ステップ移動し、速いポインターが 3/4/5... ステップ移動する場合、2 つのポインターが一致しない可能性があります。

public class Solution {
    
    
    public boolean hasCycle(ListNode head) {
    
    
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
    
    
            slow=slow.next;
            fast=fast.next.next;
            if(fast==slow){
    
    
                return true;
            }
        }
        return false;
    }
}

リンクされたリストがリングに入り始める最初のノードを見つける

leetcode
142. 环形链表 II

ここに画像の説明を挿入

リンクリストの開始位置からエントリポイントまでの距離をX、リングの長さをC、出会いポイントからエントリーポイントまでの距離をY、エントリーポイントから出会いポイントまでの距離をはCYです

高速ポインターは、低速ポインターの N 倍移動するときに出会うと仮定します。つまり、高速ポインターの速度は 2 倍であるため、低速ポインターは X+CY を移動し、高速ポインターは X+C-Y+N C を移動します。したがって、同じ時間内に高速ポインターが移動する距離は、低速ポインターの 2 倍、つまり X+C-Y+N C =2*(X+CY) であり、解は次のとおりです。 XY=(N-1)*C.
N=1 の場合、X =Y とする
と、連結リストの開始点にポインタ p1 を定義でき、合流点に p2 を定義できます.2 つのポインタは 1 つを取る一歩ずつ進み、最後にループの入り口で合流します。
N=2 の場合、p2 はループ エントリ ポイントで会うために Y+C の 2 つのポインターを歩く必要があります. N>2 の場合、2 つのポインターは常に最後に会うことができますが、時間が長くなります.

public class Solution {
    
    
    public ListNode detectCycle(ListNode head) {
    
    
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
    
    
            slow=slow.next;
            fast=fast.next.next;
            if(fast==slow){
    
    
                slow=head;
                while(slow!=fast){
    
    
                    slow=slow.next;
                    fast=fast.next;
                }
                return slow;
            }
        }
        return null;
    }
}

リンク リスト パーティション

牛客网
CM11 链表分割
现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

ここに画像の説明を挿入

例: 30 を境界として 2 つの領域を分割し、領域 <30、領域 >30、および領域
<30 は、2 つのポインター bs、be を定義します。領域 >30 は、2 つのポインターを次のように定義します。次に、cur ポインターを定義し、連結リストの先頭ノードをポイントして、連結リストをトラバースします。cur.val<30 の場合、cur が指すノードは <30 の領域に配置されます。2 番目の要素が <30 領域に配置されると、be は後方に移動します。cur が null になるまで、be.next=as で、前後の領域のノードが接続されます。

ここには落とし穴があります: ① すべての要素が >30 の場合、be は常に null になり、be.next の場合は null ポインター例外が報告されます。②aeが指している終了ノードが元の連結リストの終了ノードでない場合、つまりae.next!=nullの場合、連結リストの無限ループが発生するため、手動でae.next=nullを設定する必要があります空にする。③ これにより、新たな問題が発生 as=ae=null の場合、ae.next でヌルポインタ例外が発生する

public class Partition {
    
    
    public ListNode partition(ListNode pHead, int x) {
    
    
        // write code here
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;
        ListNode cur = pHead;
        while (cur != null) {
    
    
            if (cur.val < x) {
    
    
                if (bs == null) {
    
    
                    bs = be = cur;
                    cur = cur.next;
                }else{
    
    
                    be.next = cur;
                be = be.next;
                cur = cur.next;
                }
                
            } else {
    
    
                if (as == null) {
    
    
                    as = ae = cur;
                    cur = cur.next;
                } else {
    
    
                    ae.next = cur;
                    ae = ae.next;
                    cur = cur.next;
                }

            }
        }
        if (be == null) {
    
    
            return as;
        }
        be.next = as;
        if(ae!=null){
    
    
            ae.next = null;
        }
        return bs;
    }
}

おすすめ

転載: blog.csdn.net/qq_63983125/article/details/126923151