Fork me on GitHub

【Offer】[23] 【链表中环的入口结点】

题目描述

一个链表中包含环,如何找出环的入口结点?

思路分析

  1. 判断链表中是否有环:用快慢指针的方法,慢指针走一步,快指针走两步,如果快指针追上了慢指针,就说明有环,而且他们相遇的节点是处于环中的节点
  2. 统计环中节点的个数:利用1中返回的节点,当再次走到该节点时,正好遍历了整个环,从而可以统计出个数n。
  3. 找出入口结点:也是设置两个指针,第一个指针先向后移动n,第二个指针指向头节点,然后同时移动两个指针,它们相遇时的节点就是环的入口节点,(类似于 【链表中倒数第k个结点】 中的思路)

测试用例

  1. 功能测试:链表中包含或者不包含环;链表中有多个或者只有一
    节点。
  2. 特殊输入测试:链表头节点为nullptr指针。

Java代码

public class Offer23 {
    public static void main(String[] args) {
        test1();
        test2();
        test3();
        test4();
        test5();
    }

    public static ListNode EntryNodeOfLoop(ListNode head) {
        return Solution1(head);
    }

    /**
     * 1.判断链表中是否有环,并找出环中节点个数n 2.将一个指针向前移动n,另个一指针指向头节点 3. 然后同时移动两个指针,两个指针相遇时,就是环的入口
     * 
     * @param head
     * @return
     */
    private static ListNode Solution1(ListNode head) {
        if (head == null) {
            return null;
        }
        // 判断链表中是否有环,并找到快慢指针相遇的节点
        ListNode meetNode = MeetingNode(head);
        if (meetNode == null) {// 说明链表中没有环
            return null;
        }
        int count = 1; // 统计环中节点的个数
        ListNode pLoop = meetNode;
        while (pLoop.next != meetNode) {
            pLoop = pLoop.next;
            ++count;
        }

        ListNode p1 = head;
        for (int i = 0; i < count; i++) {
            p1 = p1.next;
        }
        ListNode p2 = head;
        while (p1 != p2) {
            p1 = p1.next;
            p2 = p2.next;
        }

        return p1;
    }

    /**
     * 设置两个指针,快指针一次走两步,慢指针一次走一步 如果快指针 追上了慢指针,就说明有环
     * 如果快指针走到尾部(null)时两个指针没有相遇,就说明两个指针没有环存在,
     * 
     * @param head
     * @return
     */
    private static ListNode MeetingNode(ListNode head) {

        if (head == null) {
            return null;
        }
        ListNode pSlow = head.next;
        if (pSlow == null) {
            return null;
        }
        ListNode pFast = pSlow.next;

        while (pSlow != null && pFast != null) {
            if (pSlow == pFast) {
                return pFast;
            }
            pSlow = pSlow.next;
            pFast = pFast.next;
            if (pFast != null) {
                pFast = pFast.next;
            }
        }
        return null;
    }

    private static void test1() {

        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);
        ListNode node4 = new ListNode(4);
        ListNode node5 = new ListNode(5);
        ListNode node6 = new ListNode(6);

        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        node5.next = node6;
        node6.next = node3;

        System.out.println("链表中有环而且有多个节点(>=3)---->");
        ListNode entryLoop = EntryNodeOfLoop(node1);
        if (entryLoop != null) {
            System.out.println(entryLoop.val);
        } else {
            System.out.println("null");
        }
    }

    private static void test2() {
        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);
        ListNode node4 = new ListNode(4);
        ListNode node5 = new ListNode(5);
        ListNode node6 = new ListNode(6);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        node5.next = node6;
        System.out.println("链表中没有环---->");
        ListNode entryLoop = EntryNodeOfLoop(node1);
        if (entryLoop != null) {
            System.out.println(entryLoop.val);
        } else {
            System.out.println("null");
        }
    }

    private static void test3() {

        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        node1.next = node2;
        node2.next = node1;

        ListNode entryLoop = EntryNodeOfLoop(node1);
        System.out.println("链表中有环,只有有两个个节点---->");
        if (entryLoop != null) {
            System.out.println(entryLoop.val);
        } else {
            System.out.println("null");
        }
    }

    private static void test4() {

        ListNode node1 = new ListNode(1);
        node1.next = node1;

        ListNode entryLoop = EntryNodeOfLoop(node1);
        System.out.println("链表中有环,只有一个节点---->");
        if (entryLoop != null) {
            System.out.println(entryLoop.val);
        } else {
            System.out.println("没有环");
        }
    }

    private static void test5() {
        ListNode entryLoop = EntryNodeOfLoop(null);
        System.out.println("传入null---->");
        if (entryLoop != null) {
            System.out.println(entryLoop.val);
        } else {
            System.out.println("null");
        }
    }

}

代码链接

剑指Offer代码-Java

posted @ 2019-08-10 15:16  这个世界~  阅读(98)  评论(0编辑  收藏  举报