問題1:判斷鏈表是否帶環
解題思路:
用兩個指針,快指針一次走兩步,慢指針一次走一步,如果兩指針相遇,那麼鏈表帶環,若兩指針不相遇,則鏈表不帶環。
pLinkNode CheckCycle(pList head) { pLinkNode fast = head; pLinkNode slow = head; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return slow; 兩指針相遇,鏈表帶環,返回相遇點 } } return NULL; //若兩指針不相遇,返回null,鏈表不帶環 }
問題2:若鏈表帶環則求環的長度
解題思路:
面試題1已經判斷過鏈表帶環,且返回兩指針相遇節點,求環長度時我們可以讓一個指針從相遇節點處開始遍歷,當再次回到相遇節點時,它走過的步數就是環的長度。
int GetCircleLength(pLinkNode meet) { pLinkNode cur = meet; int count = 0; do { cur = cur->next; count++; } while (cur != meet); return count; }
問題3:獲取環入口點
解題思路:
方法一:假設上圖是一個單鏈表,兩指針走到相遇節點時,慢指針走了x+y步,快指針走了x+y+nl步,(l爲環的長度),由於快指針速度是慢指針速度的一倍,那麼就有以下的等式:
(x+y)*2=x+y+nl;
化解可得:
x=nl-y;
那解題時我們可以用兩個指針,一個指針從鏈表的開始位置走,另一個指針從相遇的節點處開始走,也就是y,兩個指針相遇的節點就是入口點。
pLinkNode GetCycleEntryNode(pList head, pLinkNode MeetNode) { pLinkNode Entry= head; pLinkNode meet = MeetNode; while (meet != Entry) { Entry = Entry->next; meet = meet->next; } return Entry; }
方法二:
將相遇的節點處斷開,轉化爲兩條鏈表相交求交點問題,兩個指針meet和Entry分別遍歷到鏈表尾,記錄兩鏈表的長度len_l1和len_l2,然後讓較長的鏈表先走len=|len_l1 - len_l2|步,然後兩指針一起走,直到兩指針相遇,相遇的節點就是鏈表的交點,即環的入口點。
pLinkNode _GetCycleEntryNode(pList head, pLinkNode MeetNode)//鏈表帶環轉化爲鏈表相交問題獲取入口
{ pLinkNode Entry = head; pLinkNode meet = MeetNode->next; int len_head = 0; int len_meet = 0; int len = 0; while (Entry != MeetNode) //求鏈表長度 { len_head++; Entry = Entry->next; } while (meet != MeetNode)//求鏈表長度 { len_meet++; meet = meet->next; } Entry = head; meet = MeetNode->next; if (len_head > len_meet) { len = len_head - len_meet; while (len--) { Entry = Entry->next; }//較長鏈表先走len=|len_l1 - len_l2|步 } else { len = len_meet - len_head; while (len--) { meet = meet->next; }//較長鏈表先走len=|len_l1 - len_l2|步 } while (meet != Entry) { Entry = Entry->next; meet = meet->next; } //兩指針同時走,相遇節點就是環入口點 return Entry; }