1 題目及要求
1.1 題目描述
找出一個有環的單鏈表的入口節點,若沒有環則輸出空。
2 解答
2.1 題目分析
1、可以用兩個指針來解決。先定義兩個指針p1, p2連個指向鏈表頭節點。如果鏈表中的環有c個節點,則指針p2在鏈表上向前移動n步,然後兩個指針再以相同的速度移動。當p1指向環入口節點時p2已經繞着環走了一圈後又回到了環入口節點。所以解題思路如下:
1)先求環內的任意一個節點;
2)求環的長度;
3)求入口節點。
2、設置兩個指針slow和fast,分別每次向前走一步和走兩步。若有環則必會相遇,且相遇時slow肯定沒有遍歷完鏈表,而是停在環內的某一節點,而fast已經在環內走了k1圈了(1<=k1)。假設鏈表非環的部分長爲n,環部分長爲c,環入口到相遇節點的距離爲d。於是有,slow走的距離爲n+d,fast走的距離爲n+d+k1*c。由於fast是slow速度的兩倍因此有
2*(n+d) = n+d+k1*c ==> n+d = k1*c ==> n = (k1-1)*c + (c-d)
c-d爲相遇節點到環入口節點的距離,由此可見,從鏈表頭到環入口節點的距離等於k1-1圈內環長度+相遇幾點到環入口的距離。於是我們可以讓兩個指針分別從頭結點和相遇節點相同速度同時出發向前走,則必會在環入口相遇。
2.2 代碼
#include <iostream>
using namespace std;
// 鏈表節點類
struct ListNode{
int val;
ListNode *next;
ListNode(int x = 0):val(x),next(nullptr){}
};
ListNode* getCycleNode(ListNode* l1){
ListNode *np(l1);
while(np && np->next){
l1 = l1->next;
np = np->next->next;
if(l1==np)return l1;
}
return nullptr;
}
int cycleLength(ListNode* l1){
l1 = getCycleNode(l1);
if(!l1) return 0;
ListNode *np(l1->next);
int res(1);
while(np!=l1) {
++res;
np = np->next;
}
return res;
}
ListNode* getEnterNode1(ListNode* l1){
ListNode *np(l1);
int k1 = cycleLength(l1);
if(k1<1)return nullptr;
for(;0<k1;--k1)
np = np->next;
while(l1!=np){
l1=l1->next;
np=np->next;
}
return l1;
}
ListNode* getEnterNode(ListNode* l1){
ListNode *slow(l1), *fast(l1);
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
if(slow==fast) {
while(l1!=slow){
l1=l1->next;
slow=slow->next;
}
return l1;
}
}
return nullptr;
}
int main(){
ListNode ht[7]={1,2,3,4,5,6,7};
for(int k1(0);k1<6;++k1)ht[k1].next = ht+k1+1;
ListNode *np1(nullptr),*np2(nullptr);
cout << ">>>>>>>空鏈表:" << endl;
cout << "鏈表內環長度 : " << cycleLength(ht) << endl;
np1 = getEnterNode1(nullptr);
np2 = getEnterNode(nullptr);
cout << "鏈表環入口節點1: ";
np1 ? (cout << np1->val):(cout << "NULL"); cout << endl;
cout << "鏈表環入口節點2: ";
np2 ? (cout << np2->val):(cout << "NULL"); cout << endl;
cout << endl << ">>>>>>>無環鏈表:" << endl;
cout << "鏈表內環長度 : " << cycleLength(ht) << endl;
np1 = getEnterNode1(ht);
np2 = getEnterNode(ht);
cout << "鏈表環入口節點1: ";
np1 ? (cout << np1->val):(cout << "NULL"); cout << endl;
cout << "鏈表環入口節點2: ";
np2 ? (cout << np2->val):(cout << "NULL"); cout << endl;
for(int k1(6);-1<k1;--k1){
ht[6].next = ht+k1;
cout << endl << ">>>>>>>" << (7-k1) << "環鏈表:" << endl;
cout << "鏈表內環長度 : " << cycleLength(ht) << endl;
np1 = getEnterNode1(ht);
np2 = getEnterNode(ht);
cout << "鏈表環入口節點1: ";
np1 ? (cout << np1->val):(cout << "NULL"); cout << endl;
cout << "鏈表環入口節點2: ";
np2 ? (cout << np2->val):(cout << "NULL"); cout << endl;
}
return 0;
}