这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
题目
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true
。 否则,返回 false
。
进阶: 你能用 O(1)(即,常量)内存解决此问题吗?
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/li…
实例:
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
实现方案1 :暴利破解:二次访问
可以理解为检测链表的某节点能否二次到达(重复访问)的问题。
-
实现逻辑:
- 创建一个 数组容器 记录已经访问过的节点
- 每次访问到新的节点,都与容器中的记录进行匹配,若相同则存在环
- 若匹配之后没有相同节点,则存入容器,继续访问新的节点
- 直到访问节点的next指针返回null,或者当前节点与容器的某个记录相同,操作结束
-
核心:
- 数据结构:数组
- 算法思维:遍历
public boolean hasCycle1(ListNode head) {
ListNode[] array = new ListNode[10000];
while (head != null) {
// 循环遍历容器
for (int i = 0; i < array.length; i++) {
// 并与容器中的节点进行比较,已经存在过,则是环形链表
if (array[i] == head) {
return true;
}
// 不存在容器中的话,将节点信息,存入容器
if (array[i] == null) {
array[i] = head;
break;
}
}
// 向下指定 head
head = head.next;
}
return false;
}
实现方案2 :set集合 去重
Java 原生 不就提供了 可以去重的
Set
集合、既然这样尝试使用Set 来完成一下吧~~~! 其逻辑和 暴利破解一样
public boolean hasCycle2(ListNode head) {
// 使用set集合
Set<ListNode> array = new HashSet<>();
while (head != null) {
// 循环遍历 将节点 添加到集合中,添加失败,则说明节点已存在,是环形链表
if (!array.add(head)) {
return true;
}
// 向下指定 head
head = head.next;
}
return false;
}
实现方案3:快慢指针
环形连接:我们可以理解为
追击
问题 即可以想象成一个环,犹如操场跑步一样,跑的快的人 总能 绕一圈后追上 跑的慢的人。如果是直线,则不会存在追击问题
实现逻辑:
- 定义 两个变量
- 一个 慢指针
slow = head
指向 第一节点 、 一个快指针fast = head.next
指向 第二个节点
- 一个 慢指针
- 快的每次 移动2步,慢的移动1步,
- 即 fast 每次移动两个节点
fast.next.next
、 slow 每次移动一个节点slow.next
- 即 fast 每次移动两个节点
- 若:最终
fast == slow
则说明存在环 - 若:
fast == null
\fast.next != null
则 操作结束,说明不存在环
核心:
- 数据结构:两个变量
- 算法思维:遍历 + 快慢指针
public boolean hasCycle3(ListNode head) {
if (head == null || head.next == null) {
return false;
}
// 慢指针
ListNode slow = head;
// 快指针
ListNode fast = head.next;
while (fast != null && fast.next != null) {
// 当快指针 等于 慢指针时, 则说明链表 发生了循环
if (slow == fast) {
return true;
}
// 慢指针 走1步
slow = slow.next;
// 快指针 走2步
fast = fast.next.next;
}
return false;
}