链表
链表是否有环
主要实现有两种方法,参考求链表的中间节点。本质都是一样的,只要有环就能后找到
package com.vitamin.list;
/**
* 判断链表是否有环
*/
public class HasCycle {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return true;
}
}
return false;
}
public boolean hasCycleV2(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return true;
}
}
return false;
}
}
环的长度
在判断链表是否有环的基础上,进一步判断链表的长度。
- 有环,那么一个人不动,另外一个再走一圈,直至相遇,同时记录环的长度。
- 代码实现上,需要注意,在判断有环后,循环条件需要注意。
/**
* 判断有环的同时,求出环的长度
*
* @param head
* @return
*/
public int getCircleLength(ListNode head) {
int count = 0;
if (head == null || head.next == null) {
return count;
}
boolean hasCycle = false;
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
hasCycle = true;
break;
}
}
if (hasCycle) {
while (fast.next != slow) {
fast = fast.next;
count++;
}
count++;
}
return count;
}
入环节点
具体数学证明原理不是很清楚,操作方法已经记住
- 相遇后,让其中一个节点指向头节点
- 快慢指针各自走1步,直至相遇
- 返回相遇节点
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null;
}
ListNode slow = head;
ListNode fast = head;
boolean hasCycle = false;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
hasCycle = true;
break;
}
}
if (hasCycle) {
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
return null;
}