単一のリストは、典型的な問題をまとめたもの

図1は、リスト削除する所定の値に等しい **ヴァル**  すべてのノード。 

アイデアの分析:

二つの補助ポインタPREVおよびCURを定義し、ときprev.next.data = valを削除することができます

主に最初のノードに対処することを忘れないでください

 public void removeAllKey(int key) {
        ListNode prev = this.head;
        ListNode cur = this.head.next;
        while(cur != null) {
            if (prev.next.data == key) {
                prev.next = cur.next;
                cur = cur.next;
            } else {
                prev = cur;
                cur = cur.next;
            }
        }
        //处理第一个节点--最后处理
        if (this.head.data == key) {
            this.head = this.head.next;
        }
    }

 

2. 重リンクリストを逆にします。

 
①二次ポインタCUR、PREV、curNextを定義します。行く後方を聞かせてCUR、cur.next = PREV
                                                                                    前= CUR
                                                                                    CUR = curNext
curNextを見つける終わりが空になるまで②、ノードへCURポイントは、新しいヘッドです。
 
注意:
A. 元のノードを取るように設定された次のヘッダフィールドが空であります
 
 
 public ListNode reverseList() {
        if(this.head == null) {
            return null;
        }
        ListNode cur = this.head;
        ListNode prev = null;
        ListNode newHead = null;
        while (cur != null) {
            ListNode curNext = cur.next;
            if (curNext == null) {
                newHead = cur;
            }
            cur.next = prev;
            prev = cur;
            cur = curNext;
        }
        return newHead;
    }
3. 有するヘッドノードを考える ヘッド 非空単一リンクリストを、中間ノードのリストを返します。二つの中間ノードがある場合、第二の中間ノードが返されます。
 
アイデアの分析:スピードポインター法。(のみ再びリストをトラバース)
 
   public ListNode middleNode() {
//        ListNode cur = this.head;
//        int length = getlength()/2;
//        for (int i = 0; i < length; i++) {
//            cur = cur.next;
//        }
//        return cur;
        ListNode fast = this.head;
        ListNode slow = this.head;
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
4. リンクリスト、リンクリストの出力最後から二番目の入力 k個の ノードを。
 
アイデアの分析:
高速のポインタK-1のステップを移動し、ポインタが行きながら、高速と低速のポインタをさせてみましょう。高速低速ポインタポインタが中間ノードである仕上がりにノード。

 

注:最初の有効なKか否かを決定する、最も効率的な方法は、ノードの数にステップを取ること-1、非常に速くポインタが歩行であると判断されている間、fast.next = NULLであり、k不当命令リターンヌルへ。

 
 public ListNode FindKthToTail(int k) {
        if (k <= 0 || this.head == null) {
            return null;
        }
        ListNode fast = this.head;
        ListNode slow = this.head;
        for (int i = 0; i < k-1; i++) {
            if (fast.next == null) {
                return null;
            }
            fast = fast.next;
        }
        while(fast.next != null) {
            fast = fast.next;
            slow = slow.next;

        }
        return slow;
    }
5. 2は、注文とリターンされた新しいリストにリストを命じました。新しいリストは、二つのリストで構成与えられたモザイク内のすべてのノードです。
 
アイデアの分析:
順序付きリストheadAとheadBをマージします。仮想ノードnewHead、headAとheadBノードが比較されるデータを作成し、小さい方のデータがnewHeadリストヘッドノードが追加されます。
 
注意:
リストが空であるかどうかを判断するには、リストには他に直接追加されます
 
 public static ListNode mergeTwoLists1(ListNode headA, ListNode headB){
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;
        while (headA != null && headB != null) {
            if (headA.data < headB.data) {
                tmp.next = headA;
                headA = headA.next;
                tmp = tmp.next;
            } else {
                tmp.next = headB;
                headB = headB.next;
                tmp = tmp.next;
            }
        }
       //如果a为空
        if (headA == null) {
            tmp.next = headB;
        } else {
            tmp.next = headA;
        }
        return newHead.next;
    }

図6に示すように、所定の値Xへの書き込みコードがより小さい全て一覧表示されます参照するための2つの部分に分割されたXのノードは、行に以上であるX 前のノード。

分析思考:
①まず、2つの参照beginStartとbeginEnd、afterStartとafterEndが存在しなければならない
データリストノードk個の時間比は、beginStartノードにリンクされたリストのノードによって指されるときに、データがkよりも大きい場合②へafterStartノードを指します。
最初のリリースかどうかに注意を払うために時間を置きます。
③beginEndとafterStartをリンクします 

終わりのように見えますが、実際には、二つの質問を逃した:
。Aリスト場合は、以下kより全てに、戻りは問題をBSません。リスト内のすべての要素がkよりも大きい場合は、基地局の説明を直接返すことができるように、空である、プラス決意。
私たちは、BSの時間を返した場合、B。、あなたは、印刷されたリストの終了条件を見つけるnullであるが、リストが行われ、私たちはae.next最後のセットが空たいのでae.next必ずしも、空でないとき。だから、〜ちょっと実現可能

  

 public ListNode partition(int x){
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;
        ListNode cur = this.head;
        while (cur != null) {
            if (cur.data < x) {
                //判断是否为第一次加入
                if (bs == null) {
                    bs = cur;
                    be = cur;
                } else {
                    be.next = cur;
                    be = be.next;
                }
            } else {
                //判断是否为第一次加入
                if (as == null) {
                    as = cur;
                    ae = cur;
                } else {
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
       //连在一起
        if (be.next != null) {
            be.next = as;
        }
        //判断是否k是否小于所以节点
        if (bs == null) {
            return as;
        }
        if (as != null) {
            ae.next = null;
        }
        return bs;
}

7.重複ノードリストを削除し、リンクされたリストのノードは複製ソート、ノードが繰り返さを保持しない、ヘッド・ポインタ・リストを返します。

分析思考:
①重複ノードを見つけ、ノードcur.data =説明cur.next.dataは、重複データを有する場合、単一の補助変数CURトラバースリストを定義します。しかし、ノートでは、使用サイクルが決定されるように、複数のノードを繰り返しました。
②重複したノードを削除

注:
各裁判官cur.data == cur.next.data cur.nextがnullのとき、Aの裁判官が判断する必要があります。それ以外の場合は、NULLポインタ例外が発生します。
最後の中継ノードがtmp.next = nullに、次に、またノードである場合、B。

  public ListNode deleteDuplication(){
        ListNode cur = this.head;
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;
        while (cur != null) {
            //重复的节点
            if(cur.next != null && cur.data == cur.next.data) {
                //每一次都需要判断cur.next
                while (cur.next != null && cur.data == cur.next.data) {
                    cur = cur.next;
                }
                cur = cur.next;
            } else {
                tmp.next = cur;
                tmp = tmp.next;
                cur = cur.next;
            }
        }
        //最后一个节点如果也是重复的,需要将tmp.next置为空
        tmp.next = null;
        return newHead.next;
    }

 8.回文リスト。

パリンドロームはダウンカウントされ、同じ番号が数字の正のシーケンスで出てきました。このような12321として、1221年には、
どのように回文リストにそれを決定するには?
 
アイデアの分析:
中間ノードのリストを見つける①
②リバースリスト
次に行き③fast/スローフォワード頭を
 
注意:
。へはあっても数字を決定しました
B。への有料高速のリンクリストを逆転させるための注意やfast.next空の場合
 
 
    //单链表判断回文数
    public boolean chkPalindrome() {
        //为空
        if (this.head == null) {
            return false;
        }
        //一个数
        if (head.next == null) {
            return true;
        }
        //1、找到单链表的中间节点
        ListNode fast = this.head;
        ListNode slow = this.head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        //2、反转单链表
        ListNode cur = slow.next;
        while (cur != null) {
            ListNode curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
        }
        //3、fast/slow往前    head往后走
        while (this.head != slow) {
            if (this.head.data != slow.data) {
                return false;
            }
            //偶数个数
            if (this.head.next == slow) {
                return true;
            }
            this.head = this.head.next;
            slow = slow.next;
        }
        return true;
    }

二つのリストを入力し、その第1の共通のノードを見つける9。

思路分析:
①将pL指向长链表,pL指向短的链表
②让长链表先走差值步
③分别一步一步走,如果节点相同就为相交

注意:
注意计算完长度后pS、pL重新赋值,还有最后循环退出的条件

    public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null) {
            return null;
        }
        ListNode pL = headA;//永远指向长的单链表
        ListNode pS = headB;//永远指向短的单链表
        int lenA = 0;
        int lenB = 0;
        //求的lenA  lenB
        while (pL != null) {
            lenA++;
            pL = pL.next;
        }
        while (pS != null) {
            lenB++;
            pS = pS.next;
        }
        //pl、ps为空了
        pL = headA;
        pS = headB;
        //差值-》最长的单链表先走len步
        int len = lenA-lenB;
        if(len < 0) {
            pL = headB;
            pS = headA;
            len = lenB-lenA;
        }
        //让pL先走len步
        for (int i = 0; i < len; i++) {
            pL = pL.next;
        }
        //开始一起走  (pL  != pS ) {一人一步走}
        while (pL != pS) {
            pL = pL.next;
            pS = pS.next;
        }
//        if (pL == null) {
//            return null;
//        }
//        return pL;
        return pL;
    }

 

10. 给定一个链表,判断链表中是否有环。 
 

判断链表是否有环可以使用快慢指针法,快的每次走两步,慢的每次走一步。若快的和慢的相遇则有环。

 //判断链表是否有环
    public boolean hasCycle() {
        ListNode fast = this.head;
        ListNode slow = this.head;
        while (fast != null && fast.next != null)  {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                break;
            }
        }
        if (fast == null || fast.next ==null) {
            return false;
        }
        return true;
    }

 //创造一个环
    public void creteLoop() {
        ListNode cur = this.head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = this.head.next;
    }

 

11. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

当slow=fast时,将slow指向头节点。slow和fast同时往后走,当slow和fast相等时的节点就是链表开始入环的第一个节点。

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

证明:画图

12、给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

要求返回这个链表的深拷贝。 

思路分析:
①老新进行进行交替链接
②修改random
③将老新节点打开

 public Node copyRandomList(Node head) {
        if(head == null) {
            return null;
        }
        Node cur = head;
        //1、老新进行进行交替链接
        while(cur != null) {
            Node node = new Node(cur.val, cur.next, null);
            Node tmp = cur.next;
            cur.next = node;
            cur = tmp;
        }
        //2、修改random
        cur = head;
        while(cur != null) {
            if(cur.random != null) {
                cur.next.random = cur.random.next;
                cur = cur.next.next;
            } else {
                cur = cur.next.next;
            }
        }
        //3、将老新节点打开
        cur = head;
        Node newHead = cur.next;
        while(cur.next != null) {
            Node tmp = cur.next;
            cur.next = tmp.next;
            cur = tmp;
        }
        return newHead;
    }

 

最近做了挺多单链表的题,感觉虽然有的题目思路并不是特别难,但是一不小心就会造成空指针异常,因此做单链表的题要考虑全面,包括单链表的头、尾以及单链表是否为空,next是否为空。。。。

 

发布了51 篇原创文章 · 获赞 14 · 访问量 2321

おすすめ

転載: blog.csdn.net/qq_41185460/article/details/102996216