题目如图
解题思路:
一种直接的解法,很简单但是比较浪费空间:先创建一个set用于保存遍历过的节点,从头开始遍历整个链表,将遍历过的节点加入到set中,并检查正在遍历的这个节点是否存在于set中,若存在,则该节点就是要求的节点。
class Solution(object):
def detectCycle(self, head):
visited = set()
node = head
while node is not None:
if node in visited:
return node
else:
visited.add(node)
node = node.next
return None
第二种解法:快慢指针
先设两个指针,分别是slow和fast,slow一次走一步,fast一次走两步,如果存在环,那么slow和fast一定会在环内的某一个点相遇,但这个点不一定是环的入口点,设从头开始到环的入口点的距离为x,从入口点到两个点的相遇点的距离为y,环的长度为r,从开始到相遇,slow走过的距离就是t=x+n1r+y(n1为整数,走过n1圈以后相遇),fast的速度是slow的两倍,所以fast走过的距离为2t=x+n2r+y,那么fast与slow的距离为t=(n2-n1)r,是r的整数倍,所以t=x+n1r+y=(n2-n1)r,则x=(n2-2n1-1)r+r-y,即从相遇点走到入口点,然后转 (n2-2n1-1) 圈后再次回到入口点的这段时间,刚好就等于从 head 走向入口点的时间。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while (true) {
if (fast == null || fast.next == null) return null;
fast = fast.next.next;
slow = slow.next;
if (fast == slow) break;
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
}