剑指offer【C++】链表中环的入口结点

剑指offer【C++】链表中环的入口结点

题目:一个链表中包含环,请找出该链表的环的入口结点。

思路:

  • 第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。

  • 第二步,找环的长度。从环中的相汇点开始, p2不动, p1前移, 当再次相遇时,p1刚好绕环一周, 其移动即为环的长度K,使用一快一慢两个指针(比如慢指针一次走一步, 慢指针一次走两步),如果走的过程中发现快指针追上了慢指针, 说明遇见了环,而且相遇的位置一定在环内, 考虑一下环内, 从任何一个节点出现再回到这个节点的距离就是环的长度, 于是我们可以进一步移动慢指针,快指针原地不动, 当慢指针再次回到相遇位置时, 正好在环内走了一圈, 从而我们通过计数就可以获取到环的长度

  • 第三步, 求换的起点, 转换为求环的倒数第N-K个节点,则两指针left和right均指向起始, right先走K步, 然后两个指针开始同步移动, 当两个指针再次相遇时, right刚好绕环一周回到起点, left则刚好走到了起点位置


/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead == NULL || pHead->next == NULL || pHead->next->next ==NULL)
            return NULL;
        // 快慢环求环的长度
        ListNode* fast = pHead->next->next;
        ListNode* slow = pHead->next;

        
        while (fast != slow)
        {
           if (fast->next != NULL && fast->next->next != NULL)
           {
               fast = fast->next->next;
               slow = slow->next;
           }
            else 
                return NULL;
         
            
        }
        // 寻找环的长度
        int count = 1;
        ListNode* cur = fast;
        ListNode* temp = slow->next;
        //slow继续一步一步走下去,当cur and temp碰面时count是环的长度
        while(cur != temp)
        {
            temp = temp->next;
            count++;
        }
            
        
        //count 即为环的长度
        ListNode* right = pHead;
        ListNode* left = pHead;
        
        for (int i=0; i<count; i++)
            left = left->next;
        
        while(left != right)
        {
            left = left->next;
            right = right->next;
        }
        return left;
            
            
        
            
            

    }
};


猜你喜欢

转载自blog.csdn.net/haikuotiankong7/article/details/80786145