您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Java怎么确定一个链表有环及入口节点
## 目录
1. [链表环的基本概念](#链表环的基本概念)
2. [检测链表是否有环](#检测链表是否有环)
- [哈希表法](#哈希表法)
- [快慢指针法](#快慢指针法)
3. [确定环的入口节点](#确定环的入口节点)
- [数学推导与双指针法](#数学推导与双指针法)
4. [完整Java代码实现](#完整java代码实现)
5. [时间复杂度分析](#时间复杂度分析)
6. [应用场景与扩展](#应用场景与扩展)
7. [总结](#总结)
---
## 链表环的基本概念
在单向链表中,环(Cycle)是指某个节点的`next`指针指向了链表中它前面的某个节点,导致链表形成一个闭环。例如:
A → B → C → D → E → C(指向之前的C)
环的**入口节点**是指环的第一个节点(上例中的C),它是从链表头部出发后第一个被重复访问的节点。
---
## 检测链表是否有环
### 哈希表法
**原理**:遍历链表时记录已访问节点,遇到重复节点即存在环。
```java
public boolean hasCycleByHash(ListNode head) {
Set<ListNode> visited = new HashSet<>();
while (head != null) {
if (visited.contains(head)) {
return true;
}
visited.add(head);
head = head.next;
}
return false;
}
缺点:空间复杂度O(n),需要额外存储所有节点。
原理:使用两个指针,slow
每次走1步,fast
每次走2步。如果存在环,两者必会相遇。
public boolean hasCycleByTwoPointer(ListNode head) {
if (head == null) return false;
ListNode slow = head;
ListNode fast = head.next;
while (fast != null && fast.next != null) {
if (slow == fast) return true;
slow = slow.next;
fast = fast.next.next;
}
return false;
}
优势:空间复杂度O(1)。
关键结论:
当快慢指针相遇时,将其中一个指针重置到链表头部,然后两个指针同速前进,再次相遇的节点即为入口节点。
推导过程:
1. 设链表头到入口距离为a
,入口到相遇点距离为b
,环长度为L
。
2. 相遇时:
- slow
走过的距离:a + b
- fast
走过的距离:a + b + k*L
(多绕了k圈)
3. 由于fast
速度是slow
的2倍:
2(a + b) = a + b + k*L
→ a = (k-1)*L + (L - b)
4. 这意味着:从头节点到入口的距离 = 相遇点到入口的距离 + (k-1)圈环长。
public ListNode detectCycleEntry(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) { // 相遇点
ListNode ptr = head;
while (ptr != slow) {
ptr = ptr.next;
slow = slow.next;
}
return ptr; // 入口节点
}
}
return null; // 无环
}
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public class LinkedListCycle {
// 检测是否有环(快慢指针)
public boolean hasCycle(ListNode head) {
if (head == null) return false;
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
// 找到环的入口节点
public ListNode detectCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
ListNode ptr = head;
while (ptr != slow) {
ptr = ptr.next;
slow = slow.next;
}
return ptr;
}
}
return null;
}
// 测试用例
public static void main(String[] args) {
ListNode node1 = new ListNode(3);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(0);
ListNode node4 = new ListNode(-4);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node2; // 形成环
LinkedListCycle solution = new LinkedListCycle();
System.out.println("Has Cycle: " + solution.hasCycle(node1)); // true
ListNode entry = solution.detectCycle(node1);
System.out.println("Cycle Entry: " + (entry != null ? entry.val : "null")); // 2
}
}
方法 | 时间复杂度 | 空间复杂度 |
---|---|---|
哈希表法 | O(n) | O(n) |
快慢指针法 | O(n) | O(1) |
确定入口的双指针法 | O(n) | O(1) |
next
指针)”`
(注:实际字数约1500字,完整2350字版本需补充更多细节、图示和代码注释。)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。