102.带环链表

转自带环链表得几个问题
判断一个链表是否有环,如果有环,则返回入环的第一个节点,否则返回null
如果一个链表有环,遍历一个链表便永远不会到达null,否则必定会到达null。设置两个指针,刚开始都指向头节点,遍历时,一个指针每次前进一步,我们称之为慢指针,另一个每次前进两步,称之为快指针,这样,如果链表没有环,快指针必然会到达null,如果有环,两个指针必然会相交于一点。

下面再来看看如何找到入环的第一个节点,假设从头节点到入环第一个节点的长度为m,两个指针第一次相遇时的节点距离环入口点的长度为t,环的长度为n,那么此时慢指针走的长度为m+t,快指针走的长度为m+t+kn(k=0,1,2...),kn项表示快指针有可能在环内走了几圈后再与慢指针相遇,这时满足

m+t+kn = 2(m+t)
简化得到
m = (k-1)n + n - t
其中n-t项正表示了慢指针走完当前环还需要走的长度,从这里就可以看出此时如果将快指针放回头节点,然后让它每次只走一步,那么这两个指针必然会相交,并且相交的交点就是入环点。

/**
 * Definition of ListNode
 * class ListNode {
 * public:
 *     int val;
 *     ListNode *next;
 *     ListNode(int val) {
 *         this->val = val;
 *         this->next = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param head: The first node of linked list.
     * @return: the node where the cycle begins. 
     *           If there is no cycle, return null
     */
    ListNode *detectCycle(ListNode *head) {
        // write your code here
        ListNode* ptr1,* ptr2;
        if(head == NULL)
            return NULL;
        ptr1 = head ;
        ptr2 = head;

        while(ptr2->next != NULL && ptr2->next->next != NULL)
        {
            ptr1 = ptr1->next;
            ptr2 = ptr2->next->next;
            if(ptr1 == ptr2)
            {
                ptr1 = head;
                while(ptr1 != ptr2)
                {
                    ptr2 = ptr2->next;
                    ptr1 = ptr1->next;
                }
                return ptr1;
            }

        }
        return NULL;
    }
};
原文地址:https://www.cnblogs.com/narjaja/p/9762787.html