環形鏈表問題是快慢指針的一個典型應用。其實,稱其爲“有環鏈表”更爲準確。
在有環鏈表中,利用快慢指針可以解決的問題包括:
判斷鏈表是否有環、求環的入口、求環的長度、求鏈表的總長度(總節點數),等。
目錄
具體步驟:
初始,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);
}
如果覺得有用就點個贊吧~