剑指offer-面试题56:链表中环的入口结点

题目:一个链表中包含环,如何找出环的入口结点?例如下图的链表中,环的入口结点是结点3。

剑指offer-面试题56:链表中环的入口结点_第1张图片

       思路:受面试题15的启发,可以用两个指针来解决这个问题。定义p1和p2两个指针,均指向链表的头结点,如果链表中的环有n个结点,指针p1现在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向环的的入口结点时,第一个指针已经围绕着环走了一圈又回到了入口结点。为什么是p1先走n步?书上这里略过没讲,这里证明一下:假设有一个指针p指向链表头结点,设不在环中的结点个数为m,那么指针p走m步即可第一次到达入口结点,例如图中指针先走两步即可到达入口结点。指针继续向后走,再走n步,因为环的最后一个结点指向了入口结点,又回到了入口结点,所以第二次达到入口结点总共需要m+n步,这才有两个指针的时候p1需要先走n步。

       现在关键的问题是求出环的结点个数,是想一下,如果我们的结点已经在环中,那么走一圈还会回到刚开始的结点,这样就可以统计环中结点的个数。问题又转化为找出任意一个环中的结点。环形链表有什么性质?那就是如果定义两个指针,一个指针每次走两步,另一个指针每次走一步,最终它们会再次相遇,所以相遇的那个结点就是我们要找的环内的结点,问题解决!

ListNode* MeetingNode(ListNode* pHead)
{
    if(pHead == NULL)
        return NULL;
        
    ListNode* p1 = pHead;
    ListNode* p2 = pHead;
    while(p1 != NULL && p2 != NULL)
    {
        if(p1 == p2)
            return p1;
        p1 = p1->m_pNext;
        p2 = p2->m_pNext;
        if(p2 != NULL)
            p2 = p2->m_pNext;
    }
    
    return NULL;
}

ListNode* EntryNodeOfLoop(ListNode* pHead)
{
    if(pHead == NULL)
        return NULL;
        
    ListNode* nodeInLoop = MeetingNode(pHead);
    int sizeOfLoop = 1;
    if(nodeInLoop)
    {
        ListNode* pNode = nodeInLoop->m_pNext;
        while(pNode != nodeInLoop)
        {
            pNode = pNode->m_pNext;
            ++sizeOfLoop;
        }
        
        ListNode* p1 = pHead;
        ListNode* p2 = pHead:
        for(int i = 0; i < sizeOfLoop; ++i)
            p1 = p1->m_pNext;
            
        while(p1 != p2)
        {
            p1 = p1->m_pNext;
            p2 = p2->m_pNext;
        }
        return p1;
    }
    
    return NULL;
}


你可能感兴趣的:(剑指offer-面试题56:链表中环的入口结点)