链表中环的入口结点
一个链表中包含环,请找出该链表的环的入口结点。
方法一:维护一个哈希表
1、哈希容器set。
2、加入元素,通过返回值判断加入失败则是入口结点。
3、注意非环对空指针的判断。
空间复杂度比较大,如果链表很长,这个方法不再合适,但是这是一个思路扩展,显然对于hash,用处有很多。
方法二:两个指针
1、先找汇聚点。
2、找到汇聚点后,fast比slow多跑的距离k*n和slow跑的距离x是相等的。其中n为环结点数。此时slow距汇聚点为t,一个回到起点跑x-t,另一个继续向前跑k*n-t。
方法三:next置空
1、两指针一前一后,pre,cur。
2、后的将next置空,pre->next=nullptr,pre=cur,cur=cur->next。
3、当cur为空的时候,表示此处曾经来过,并且断开了链表。返回pre。
注意:此方法必须有环,或是提前判断。但是破坏了链表,不可取。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
//O(1)空间
if(!pHead) return nullptr;
ListNode *slow=pHead,*fast=pHead;
/*寻找汇聚点此时2*X=X+k*n
*fast=2X,slow=x,环=n:表示结点个数
*X =k*n
*重新开始走,表示将X(k*n)剩余部分走完。
*/
while(fast){
if(fast->next) fast=fast->next->next;
else return nullptr;
slow=slow->next;
if(fast==slow) break;
}
for(slow=pHead;slow!=fast;slow=slow->next,fast=fast->next);
return slow;
/*空间复杂度过高
unordered_set<ListNode*> ps;//可以维护一个容器装地址
ListNode *cur=pHead;//set插入是有返回状态的!!!
while(ps.insert(cur).second&&cur!=nullptr){
cur=cur->next;
}
if(!cur) return nullptr;
return cur;
*/
}
};