判断一个单链表中是否有环

思路:快慢指针实现

用两个指针,一个指针一次走一步,另一个指针一次走两步,如果存在环,则这两个指针会在环内相遇,时间复杂度为O(n)

  /**
     * 检测单链表中是否有环
     */
    public static boolean hasCircle(ListNode head) {
        if(null == head) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                return true;//两个指针相遇
            }
        }
        return false;
    }

拓展1:如果单链表有环,找出环的入口节点(环的连接点)

  /**
     *如果单链表有环,找出环的入口节点(环的连接点)。
     *这里先证明一个定理:碰撞点到连接点的距离=头指针到连接点的距离
     *假设单链表的总长度为L,头结点到环入口的距离为a,环入口到快慢指针相遇的结点距离为x,环的长度为r,
     *慢指针总共走了s步,则快指针走了2s步。另外,快指针要追上慢指针的话快指针至少要在环里面转了一圈多(假设转了n圈加x的距离)
     *得到以下关系:
     *s = a + x
     *2s = a + nr + x
     *=>a + x = nr
     *=>a = nr - x //入口点
     */
    public static ListNode searchEntranceNode(ListNode head) {
        ListNode slow=head;//p表示从头结点开始每次往后走一步的指针
        ListNode fast=head;//q表示从头结点开始每次往后走两步的指针
        while(fast !=null && fast.next !=null) 
        {
            slow=slow.next;
            fast=fast.next.next;
            if(slow==fast) {
                break;//p与q相等,单链表有环
            }
        }
        if(fast == null || fast.next == null){
            return null;
        }
        slow=head;
        while(slow != fast)
        {
            slow=slow.next;
            fast=fast.next;
        }
        return slow;
    }
  public static ListNode searchEntranceNode1(ListNode head){
        if(head == null || head.next == null)
            return null;
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null ){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                fast=slow;//相遇点
                slow=head;
                while(slow != fast){
                    slow = slow.next;
                    fast = fast.next;
                }
                if(slow == fast)
                    return fast;
                }
        }
        return null;
    }

拓展二:求链表中环的长度

    /**
     * 求环的长度
     */
    public static int countCircleSize(ListNode head) {
        ListNode entranceNode = searchEntranceNode1(head);//环的入口点
        if(entranceNode == null) {
            return 0;
        }
        ListNode slow = entranceNode.next;
        int size = 1;
        while(slow != entranceNode) {
            slow = slow.next;
            size++;
        }
        return size;
    }

 

posted @ 2019-03-21 16:12  提拉没有米苏  阅读(900)  评论(0编辑  收藏  举报