题目
给定个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
进阶:你能用 O(1)内存解决此问题吗?
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
提示:
链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引
分析和解答
方法1
可以使用Hash表来解决:
1、从表头结点开始,逐个遍历链表中的每个结点。
2、对于每个结点,检查该结点的地址是否存在于散列表中。
3、如果存在,则表明当前访问的结点已经被访问过了。出现这种情况只能是因为给定链表中存在环。
4、如果散列表中没有当前结点的地址,那么把该地址插入散列表中。重复上述过程,直至到达表尾或者找到环。
这个方法时间复杂度为O(n),用于扫描链表。空间复杂度为O(n),用于散列表的空间开销。
但是题目进阶要求是能用 O(1)内存解决此问题,所以这个方法我们不做具体实现,留给同学们自行实现。
方法2
对于判断是否存在环形链表,其实存在着一种通用解法,该方法称为Floyd环判定算法。该方法使用两个在链表中具有不同移动速度的指针。一旦它们进入环,就成为一个环形追及问题,两者肯定相遇,只要相遇就表示存在环。
在工程实践中,一般两个指针每次分别移动1个结点和2个结点,其他的移动速度也能解决这个问题,但是会增加算法的复杂度。
代码
/**
* @author :
* @description :(LeetCode-141) 环形链表
* 给定个链表,判断链表中是否有环。
* 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
* 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。
* 如果 pos 是 -1,则在该链表中没有环。
* 注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
* 如果链表中存在环,则返回 true 。 否则,返回 false 。
* 进阶:你能用 O(1)内存解决此问题吗?
*/
public class LinkedListCycle_141 {
public boolean hasCycle(ListNode head) {
if (head == null) return false;
ListNode slowPtr = head, fastPtr = head;
while (fastPtr.next != null && fastPtr.next.next != null) {
slowPtr = slowPtr.next;
fastPtr = fastPtr.next.next;
if (slowPtr == fastPtr)
return true;
}
return false;
}
}