链表OJ题目详解(10)---求链表入环的第一个节点

文章介绍了两种方法来解决链表中环的检测及入口点找到的问题。首先使用快慢指针找到环的相遇点,然后从相遇点和头节点同时开始每次前进一步,最终相遇点即为入环口。另一种方法是将相遇点与链表断开,转化为寻找两个相交链表的公共节点问题。
摘要由CSDN通过智能技术生成

题目描述

这道题显然是上一道题的一个进阶,上一道题是判断链表是否有环,这道题是求环的入口点

思路一:

①定义快慢指针,若链表带环,求出链表在环中的相遇点

②再定义一个指针meet,meet从快慢指针相遇点开始走,头指针head从链表的头开始走,两指针每次都走一步,两指针的相遇点即为链表入环口

思路合理性的证明:

思路一中的第一点上道题我们已经说明过了,下面是对思路一第二点的阐释

 这里面有一个重要等式,就是 快指针走的路程 是 慢指针的两倍

以下过程为常见错误!!!

L + C + X  = 2(L+X)

解得 L = C -X

因此meet和head相遇点即为入环点

错误原因:误认为快指针追上慢指针时只多走了一圈,但实际快指针在慢指针入环之前可能已经走了很多圈了

 正确等式

L + n*C + X  = 2(L+X)

n*C =  L + X

L = n * C - X     这个式子说明了meet走n圈再倒退X(就是环的入口点) 就是L的距离,那head和meet不就在环的入口点相遇了吗?

上式还可以写成 L = (n-1)*C + C-X , 也就是meet指针走n-1圈再走 C - X ,也就来到了环的入口点

这就说明了思路一的正确性

完整代码

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode * fast = head;
    struct ListNode * slow = head;
    while(fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
        {
            struct ListNode* meet = fast;
            while(meet != head)
            {
                head = head->next;
                meet = meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

思路二:从fast与slow相遇的节点处断开,转化成之前讲过的求两个相交链表第一个公共节点的问题

 完整代码

 struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
	struct ListNode* tailA = headA;
	struct ListNode* tailB = headB;
	int lenA = 1, lenB = 1;
	while (tailA->next)
	{
		tailA = tailA->next;
		lenA++;
	}
	while (tailB->next)
	{
		tailB = tailB->next;
		lenB++;
	}
	if (tailA != tailB)
	{
		return NULL;
	}
	//长的先走差距步
	int gap = abs(lenA - lenB);
	struct ListNode* longList = headA;
	struct ListNode* shortList = headB;
	if (lenA < lenB)
	{
		longList = headB;
		shortList = headA;
	}
	while (gap--)
	{
		longList = longList->next;
	}
	while (longList != shortList)
	{
		longList = longList->next;
		shortList = shortList->next;
	}
	return longList;
}

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while(fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(slow == fast)
        {
            struct ListNode* meet = fast;
            struct ListNode* rhead = meet->next;
            meet->next = NULL;
            struct ListNode* result = getIntersectionNode(head, rhead);
            return result;
        }
    }
    return NULL;
}

 本篇博客就介绍到此,欢迎大家交流指正~

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值