LeetCode142-环形链表 II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。

在这里插入图片描述
示例 2:

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。

在这里插入图片描述
示例 3:

输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。

在这里插入图片描述

进阶:

  • 你是否可以不用额外空间解决此题?

一、思路

(一)暴力法

使用set去重,然后判读set的大小与链表长度是否一致,不一致则表示刚刚放入的集合的那个node是重复的

C++代码

class Solution {
public:
	ListNode *detectCycle(ListNode *head) {
		set<ListNode *> detect;
		int len = 0;
		while (head != NULL) {
			detect.insert(head);
			len++;

			if (len != detect.size())
				break;
			head = head->next;
		}
		return head;
	}
};

执行效率:
在这里插入图片描述

(二)双指针法

设置两个指针,一个是快指针fast、一个是慢指针slow,将快指针的移动速度设为慢指针的两倍

设置循环,若在某次循环中fast追上了slow(实际上是超了一圈),表明这个链表存在回环

之后需要找到回环的第一个位置,怎么找呢?

假设入口为节点A,它离链表中的第一个节点的距离为a,快指针与慢指针相遇的节点为B,设节点B离回环的第一个节点的距离为b,则节点B离链表的第一个节点的距离为:(a+b)

我们知道此时快指针fast经过的节点数量是慢指针slow的两倍,即:2*(a+b)

于是用快指针走过的距离减去慢指针走过的距离,得到的就是快指针比慢指针多走的距离,这里,我们知道,快指针与慢指针相遇时,快指针一定比慢指针多走了一圈回环,因此可知回环的长度为:(a+b)

我们想要知道的是节点A,现在节点A离第一个节点的距离为a,而慢指针所在的节点B现在离节点的距离是b,根据回环长度,可知慢指针再经过a个节点后便能到达节点A,而第一个节点(head)经过a个节点后也恰好到达节点A,于是尽管我们并不知道a是多少,但是可以利用这个条件判断是否到达A点

C++代码:

class Solution {
public:
	ListNode *detectCycle(ListNode *head) {
		// 1 判断是否存在回环
		ListNode *fast = head, *slow = head;
		bool hasCycle = false;
		while (fast != NULL) {
			// fast移动两步,slow移动一步
			fast = fast->next;
			if (fast == NULL)
				return NULL;
			fast = fast->next;
			slow = slow->next;
			if (fast == slow) {
				hasCycle = true;
				break;
			}	
		}
		if (hasCycle) {
			while (slow != head) {
				slow = slow->next;
				head = head->next;
			}
			return head;
		}
		return NULL;
	}
};

执行效率:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lyd1995/article/details/89363393