55.链表中环的入口结点

题目

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

思路

  • 首先用两个快慢指针,快指针一次走一步,慢指针一次走两步。如果快指针走到了nullptr,说明没有环。如果他俩相遇,则说明有环。记录下相遇的位置。
  • 用两个指针,一个指向链表首部,一个指向前面快慢指针相遇的位置。两个指针同时往前走,最后相遇的地方即为环的入口结点。

证明

  • 如果有环,快慢指针一定会相遇。
    • 如果有环,在某一时刻,快慢指针都会在在环里,此时快指针一次走两步,慢指针一次走一步,所以每次快慢指针的距离缩短,最终会相遇。
  • 指向链表首部的指针和指向快慢指针相遇位置的指针,同时向前走,相遇的地方为链表入口结点。在这里插入图片描述
    • 如上图所示为一个链表。到相遇点的时候有:
    • 慢指针走过的距离有 a + b a+b a+b
    • 快指针走过的距离为 a + b + k ( b + c ) a+b+k(b+c) a+b+k(b+c),k表示快指针走过的圈数, k > = 1 k>=1 k>=1
    • 快指针的速度是慢指针的两倍,所以有 a + b + k ( b + c ) = 2 ( a + b ) a+b+k(b+c)=2(a+b) a+b+k(b+c)=2(a+b),化简得 a = ( k − 1 ) ( b + c ) + c a=(k-1)(b+c)+c a=(k1)(b+c)+c
    • 对于 a = ( k − 1 ) ( b + c ) + c a=(k-1)(b+c)+c a=(k1)(b+c)+c的理解。指针从链表头开始走 a a a步会到达入口结点,指针从快慢指针相遇点走若干圈后再走c的距离也能到达入口结点。

代码

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if ( pHead == nullptr )
            return nullptr;
        
        // 快慢指针求交点
        ListNode* jointNode = findJoinNode( pHead );
        // 求入口结点
        ListNode* entryNode = findEntryNode( pHead, jointNode );
        
        return entryNode;
    }
    
    ListNode* findJoinNode( ListNode* pHead ) {
        ListNode* slow = pHead, fast = pHead;
        ListNode* node = nullptr;
        
        while ( fast && fast->next ) {
            slow = slow->next;
            fast = fast->next->next;
            
            if ( slow == fast ) {
                node = slow;
                break;
            }
        }
        
        return node;
    }
    
    ListNode* findEntryNode( ListNode* pHead, ListNode* jointNode ) {
        if ( jointNode == nullptr )
            return nullptr;
        
        while ( pHead != jointNode ) {
            pHead = pHead->next;
            jointNode = jointNode->next;
        }
        
        return pHead;
    }
};
``
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值