面试题——链表中环的入口节点

AcWing 34 链表中环的入口节点

题目

给定一个链表,若其中包含环,则输出环的入口节点。

若其中不包含环,则输出null

样例

在这里插入图片描述

给定如上所示的链表:
[1, 2, 3, 4, 5, 6]
2
注意,这里的2表示编号是2的节点,节点编号从0开始。所以编号是2的节点就是val等于3的节点。

则输出环的入口节点3.

思路

​ 这道题解法很巧妙,有一股数学的气息,首先我们回忆一下怎么确定一个链表中是否存在环

​ 我们是使用快慢指针的方式来确定链表中是否存在环的,两个指针onetwo都从链表的head出发,one每次走一个节点,two每次走两个节点,如果链表存在环的情况下,两个指针一定会在环中的某个位置相遇,否则如果two走到了链表结尾,说明链表没有环

​ 那我们如何确定链表中环的入口节点呢?请看这张图

在这里插入图片描述

​ 首先,我们假设入口节点b距离head节点a的距离为x,两个指针相遇的点c距离b点的长度是y,那么,one指针走到b需要x步,而此时two指针已经走了2x步,正在环中某处(假设链表存在环),而当one再走y步就会到达两个指针相遇的c点,再次期间,two同样会走2y步,所以,在one到达b点时,two实际距离by步,也就是说,这个环的长度为x + y,所以我们可以得到,当twoc点时,它距离b点差x

​ 通过这个结论,我们可以在两个指针相遇时,让one指回头节点,此时one距离b点差x步,two距离b点也为x步,从这个时候开始,我们让两个指针每次走一个单位,当两个指针再次相遇时,这个点就是b点,代码如下:

代码

class Solution {
public:
    ListNode *entryNodeOfLoop(ListNode *head) {
		auto i = head, j = head;
		while (i && j) {
			i = i->next;
			j = j->next;
			if (j) {
				j = j->next;
				if (!j) return 0;
			}
			if (i == j) {
				i = head;
				while (i != j) {
					i = i->next;
					j = j->next;
				}
				return i;
			}
		}
		return 0;
    }
};
发布了72 篇原创文章 · 获赞 89 · 访问量 6522

猜你喜欢

转载自blog.csdn.net/scfor333/article/details/104951421