环形链表
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 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 <= 105pos的值为-1或者链表中的一个有效索引
进阶:你是否可以使用 O(1) 空间解决此题?
解题:
方法一:哈希表
思路与算法
一个非常直观的思路是:我们遍历链表中的每个节点,并将它记录下来;一旦遇到了此前遍历过的节点,就可以判定链表中存在环。借助哈希表可以很方便地实现。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode pos = head;
// 这个很重要!!!
Set<ListNode> visited = new HashSet<ListNode>();
while (pos != null) {
if (visited.contains(pos)) {
return pos;
} else {
visited.add(pos);
}
pos = pos.next;
}
return null;
}
}
复杂度分析
时间复杂度:O(N),其中 N 为链表中节点的数目。我们恰好需要访问链表中的每一个节点。
空间复杂度:O(N),其中 N 为链表中节点的数目。我们需要将链表中的每个节点都保存在哈希表当中。
作者:力扣官方题解
链接:https://leetcode.cn/problems/linked-list-cycle-ii/solutions/441131/huan-xing-lian-biao-ii-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法二:快慢指针
这是一个经典的链表环检测问题,可以通过快慢指针的方法解决。具体步骤如下:
-
使用两个指针,一个慢指针 slow 和一个快指针 fast,初始时都指向链表的头节点 head。
-
快指针 fast 每次前进两步,慢指针 slow 每次前进一步,直到两个指针相遇,或者快指针 fast 到达链表的末尾(即指向 null)。
-
如果快指针 fast 到达了链表的末尾,说明链表中没有环,返回 null。
-
如果两个指针相遇(即 slow == fast),说明链表中存在环,此时将慢指针 slow 重新指向链表头节点 head。
-
接下来,让慢指针 slow 和快指针 fast 每次都前进一步,直到两个指针再次相遇。相遇点即为环的入口节点。
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
public class LinkedListCycle {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
boolean hasCycle = false;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
hasCycle = true;
break;
}
}
if (!hasCycle) {
return null;
}
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
public static void main(String[] args) {
// 创建链表
ListNode head = new ListNode(3);
ListNode node1 = new ListNode(2);
ListNode node2 = new ListNode(0);
ListNode node3 = new ListNode(-4);
head.next = node1;
node1.next = node2;
node2.next = node3;
node3.next = node1; // 创建环
LinkedListCycle solution = new LinkedListCycle();
ListNode cycleNode = solution.detectCycle(head);
if (cycleNode != null) {
System.out.println("链表开始入环的第一个节点的值为: " + cycleNode.val);
} else {
System.out.println("链表中不存在环");
}
}
}
扩展:
是否有环:
// 链表中是否有环
public ListNode getNodeInloop(ListNode head) {
if (head == null || head.next == null) {
return null;
}
ListNode slowListNode = head.next;
ListNode fastListNode = slowListNode.next;
while (fastListNode != null && slowListNode != null) {
if (slowListNode == fastListNode) {
return slowListNode;
}
slowListNode = slowListNode.next;
fastListNode = fastListNode.next;
if (fastListNode.next != null) {
fastListNode = fastListNode.next;
}
}
return null;
}
删除倒数第n个指针:
// 删除倒数第几个点
public ListNode removeNodeFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode frontListNode = head, backListNode = dummy;
for (int i= 0; i < n; i++) {
frontListNode = frontListNode.next;
}
while (frontListNode != null) {
frontListNode = frontListNode.next;
backListNode = backListNode.next;
}
backListNode.next = backListNode.next.next;
return dummy.next;
}
首个字段--环大小方案:
// 获取环的首个节点--环大小方案
public ListNode detectCycleFastAndSlow(ListNode head) {
ListNode inLoopListNode = getNodeInloop(head);
if (inLoopListNode == null) {
return null;
}
int loopCount = 1;
// 先走n步
for (ListNode node = inLoopListNode; node.next != inLoopListNode; node = node.next) {
loopCount++;
}
ListNode fastListNode = head, slowListNode = head;
for (int i = 0; i < loopCount; i++) {
fastListNode = fastListNode.next;
}
while (fastListNode != slowListNode) {
fastListNode = fastListNode.next;
slowListNode = slowListNode.next;
}
return slowListNode;
}
5万+

被折叠的 条评论
为什么被折叠?



