环形链表问题是快慢指针的一个典型应用。其实,称其为“有环链表”更为准确。
在有环链表中,利用快慢指针可以解决的问题包括:
判断链表是否有环、求环的入口、求环的长度、求链表的总长度(总节点数),等。
目录
具体步骤:
初始,slow和fast都从链表头节点head开始,fast每次走2步,slow每次走1步。如果fast走到链表尾部,说明链表无环;否则,链表有环,fast和slow必定在环中的某个节点第一次相遇。【判断是否有环get】
第一次相遇后,令fast重新指向head,slow不变。二者重新开始以相同速度移动,则第二次相遇时的节点必是环的入口节点。【环的入口get】在此过程中,若记录下fast移动的步数则是链表中非环部分的长度LengthLine。【非环的长度get】
已知环的入口节点后,令一个指针绕环走一圈,就得到了环的长度LengthLoop。【环的长度(2) get】LengthLine + LengthLoop即为链表的总长度。【链表总长度get】
如果只求环的长度,还有另一种方法:fast和slow第一次在环中相遇后,以此作为起点,fast仍然每次走2步,slow每次走一步。当两个指针第二次在环中相遇时,fast恰好比slow多走了一圈。因此用fast走过的步数减去slow走过的步数,则为环的长度。【环的长度(1) get】
Java代码如下:
一 判断链表是否有环
//快慢指针
public class Solution {
public boolean hasCycle(ListNode head) {
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 EntryNodeOfLoop(ListNode pHead)
{
ListNode slow = pHead, fast = pHead;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(slow == fast)
break;
}
//无环:
if(fast == null || fast.next == null)
return null;
//有环:
fast = pHead;
while(slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
三 有环链表中环的长度
3.1 方法一:第一次相遇后继续走,直到第二次相遇
//求环的长度 (方法一:第一次相遇后继续走,直到第二次相遇)
public static int LengthOfLoop(ListNode head) {
ListNode slow = head, fast = head;
while(head != null && head.next != null) {
slow = slow.next;
fast = fast.next.next;
if(slow == fast)
break;
}
//无环
if(fast == null || fast.next == null)
return -1;
//有环
int countSlow = 0, countFast = 0;
while(true) {
slow = slow.next;
fast = fast.next.next;
countSlow += 1;
countFast += 2;
if(slow == fast)
break;
}
return (countFast - countSlow);
}
3.2 方法二:先求出环的入口节点
注:此函数的输入为环的入口节点
//求环的长度(方法二:先求出环的入口节点enter)
//... ...
//... ...
public static int LengthOfLoop2(ListNode enter) {
int count = 1;
ListNode cur = enter.next;
while(cur != enter) {
count++;
cur = cur.next;
}
return count;
}
四 有环链表的总长度
分别求出链表中 线性部分的长度LengthLine、环形部分的长度LengthLoop,二者相加即为链表总长度。
//求有环链表总长
public static int LengthOfList(ListNode head) {
ListNode slow = head, fast = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(slow == fast)
break;
}
fast = head;
int lengthLine = 0; //非环部分的长度
while(slow != fast) {
slow = slow.next;
fast = fast.next;
lengthLine++;
}
System.out.println("LengthLine: " +lengthLine);
//此时fast和slow都指向环的入口节点
int lengthLoop = 1; //环的长度
fast = fast.next;
while(fast != slow) {
fast = fast.next;
lengthLoop++;
}
System.out.println("LengthLoop: " +lengthLoop);
return (lengthLine + lengthLoop);
}
如果觉得有用就点个赞吧~