链表中环的入口结点

Posted hesper

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表中环的入口结点相关的知识,希望对你有一定的参考价值。

链表中环的入口结点

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

第一步两个节点, 一快一慢, 若有环则相遇

当快慢节点相遇时, 慢结点走了x个节点, 快结点恰巧走了2x个节点, 2x = k*n + x, k为1, 2,..., 此时令其中一个节点等于头结点, 然后以相同速度移动两个节点, 相遇时恰好为环的入口节点

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if ((nullptr == pHead) || (nullptr == pHead->next)) {
            return nullptr;
        }
        ListNode *pNode1 = pHead;
        ListNode *pNode2 = pHead;
        
        while ((nullptr != pNode2) && (nullptr != pNode2->next)) {
            pNode1 = pNode1->next;
            pNode2 = pNode2->next->next;
            
            if (pNode1 == pNode2) {
                pNode2 = pHead;
                while (pNode1 != pNode2) {
                    pNode1 = pNode1->next;
                    pNode2 = pNode2->next;
                }
                return pNode1;
            }
        }
        return nullptr;
    }
};

利用快慢节点确定有无环若有则返回相交节点, 否则返回nullptr

然后利用相交节点确定环的中节点的个数N

再让一个节点指向头结点, 一个指针指向距头结点第N个节点, 然后以相同速度同时移动两个节点, 相遇时即为环的入口点

class Solution {
public:
    // 利用快慢节点移动速度不同, 若有环, 快慢节点必相遇
    ListNode *MeetingNode(ListNode* pHead) {
        if (nullptr == pHead) {
            return nullptr;
        }
        
        ListNode *pSlow = pHead->next;
        if (nullptr == pSlow) {    // 若只有两个节点则不能组成环
            return nullptr;
        }
        
        ListNode *pFast = pSlow->next;
        
        while((nullptr != pSlow) && (nullptr != pFast)) {
            if (pSlow == pFast) {
                return pSlow;
            }
            pSlow = pSlow->next;
            //pFast = pSlow->next;    // 没有判断pFast移动后是否是空节点
            pFast = pFast->next;    // 需要判断pFast是不是空节点
            if (nullptr != pFast) {
                pFast = pFast->next;
            }
        }
        
        return nullptr;
    }
    
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        ListNode *meetingNode = MeetingNode(pHead);
        if (nullptr == meetingNode) {
            return nullptr;
        }
        
        // 得到环节点的数目
        ListNode *ct = meetingNode;
        int counts = 1;
        while (ct->next != meetingNode) {
            counts++;
            ct = ct->next;
        }
        
        // 确定环的入口
        ListNode *pNode1 = pHead;    // pNode1指向头结点
        ListNode *pNode2 = pHead;    // pNode2先移动counts节点数目
        for (int i = 0; i < counts; i++) {
            pNode2 = pNode2->next;
        }
        while (pNode1 != pNode2) {
            pNode1 = pNode1->next;
            pNode2 = pNode2->next;
        }
        
        return pNode1;
    }
};
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/

以上是关于链表中环的入口结点的主要内容,如果未能解决你的问题,请参考以下文章

链表中环的入口结点

链表中环的入口结点

剑指OFFER 链表中环的入口结点

链表中环的入口结点

牛客网高频算法题系列-BM7-链表中环的入口结点

55.链表中环的入口结点