哈希表法
-
算法思路:遍历链表,使用一个哈希表来记录已经访问过的节点。对于链表中的每个节点,检查该节点是否已经在哈希表中。如果在哈希表中,说明链表存在环;如果遍历到链表的末尾(即节点为null)都没有在哈希表中发现重复节点,说明链表无环。
-
代码实现:
iniclass ListNode { int val; ListNode next; ListNode(int x) { val = x; next = null; } } //哈希表法处理链表是否有环 public boolean hasCycleHash(ListNode head) { HashSet<ListNode> visited = new HashSet<ListNode>(); ListNode current = head; while (current != null) { // 如果当前节点已经在哈希表中,说明有环 if (visited.contains(current)) { return true; } // 将当前节点添加到哈希表中 visited.add(current); current = current.next; } return false; // 遍历完链表没有发现环 } public static void main(String[] args) { //测试无环场景 ListNode nodeA = solution.new ListNode(1); ListNode nodeB = solution.new ListNode(2); ListNode nodeC = solution.new ListNode(3); ListNode nodeD = solution.new ListNode(4); ListNode nodeE = solution.new ListNode(5); nodeA.next = nodeB; nodeB.next = nodeC; nodeC.next = nodeD; nodeD.next = nodeE; // 无环 boolean resultNoCycle = solution.hasCycleHash(nodeA); System.out.println("哈希法处理:链表是否有环: " + resultNoCycle); // 输出: 链表是否有环: false }
结果展示:
arduino
哈希法处理:链表是否有环: false
快慢指针法
-
算法思路:设置两个指针,一个慢指针(slow)和一个快指针(fast)。慢指针每次移动一个节点,快指针每次移动两个节点。如果链表没有环,快指针会先到达链表末尾;如果链表有环,快指针会在环内追上慢指针,即快慢指针会相遇,此时说明链表存在环。
-
代码实现:
ini//创建节点信息 class ListNode { int val; ListNode next; ListNode(int x) { val = x; next = null; } } //快慢法 public boolean hasCycle(ListNode head) { if (head == null || head.next == null) { return false; // 链表为空或只有一个节点,不可能有环 } // 使用快慢指针法检测环 ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) { // 慢指针走一步,快指针走两步 slow = slow.next; fast = fast.next.next; // 快慢指针相遇,说明有环 if (slow == fast) { return true; } } return false; // 没有环 } //测试 public static void main(String[] args) { LinkedListCycle solution = new LinkedListCycle(); ListNode node1 = solution.new ListNode(3); ListNode node2 = solution.new ListNode(2); ListNode node3 = solution.new ListNode(0); ListNode node4 = solution.new ListNode(-4); node1.next = node2; node2.next = node3; node3.next = node4; node4.next = node2; // 创建环 // 测试链表是否有环 //测试无环场景 node4.next = null ; // 无环 boolean result = solution.hasCycle(node1); System.out.println("链表是否有环: " + result); // 输出: 链表是否有环: true //测试有环场景 ListNode entryNode = solution.detectCycle(node1); if (entryNode != null) { System.out.println("环的入口节点值: " + entryNode.val); // 输出: 环的入口节点值: 2 } else { System.out.println("链表无环"); } }
结果展示:
makefile
链表是否有环: true
环的入口节点值: 2
寻找环的入口
代码实现:
ini
//找到环的入口节点
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null; // 链表为空或只有一个节点,不可能有环
}
// 初始化快慢指针
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; // 没有环
}
// 找到环的入口节点
//p1从头开始,p2从相遇点开始
ListNode p1, p2;
p1 = head;
p2 = slow;
while (p1 != p2) {
p1 = p1.next;
p2 = p2.next;
}
return p1; // 返回环的入口节点
}