剑指offer55_链表中环的入口结点_题解
链表中环的入口结点
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
分析
方案一:双指针法
算法流程:
- 双指针第一次相遇:设两指针 \(pslow\),\(pfast\) 指向链表头部 \(phead\),\(pfast\) 每轮走 \(1\) 步,\(pslow\) 每轮走 \(1\) 步
- 第一种结果:\(pfast\) 走过链表末端,说明链表无环,直接返回 \(null\)
- 第二种结果:当 \(pfast == pslow\) 时,两指针在环中 第一次相遇
- \(pslow\) 指针位置不变,将 \(pfast\) 指针重新指向链表头部结点 \(phead\),\(pslow\) 和 \(pfast\) 同时每轮往前走 \(1\) 步
- 当 \(pfast==pslow\) 时,两指针第二次相遇,并同时指向链表环入口,返回 \(pslow\) 指针指向的结点
代码
/*
1.时间复杂度:O(n)
2.空间复杂度:O(1)
*/
class Solution
{
public:
ListNode *EntryNodeOfLoop(ListNode *pHead)
{
ListNode *pslow = pHead, *pfast = pHead;
while (pfast && pfast->next)
{
pslow = pslow->next;
pfast = pfast->next->next;
//快慢指针相遇
if (pslow == pfast)
{
pslow = pHead;
while (pslow != pfast)
{
pslow = pslow->next;
pfast = pfast->next;
}
return pslow;
}
}
return NULL;
}
};
方法二:哈希
算法流程:
- 初始化 \(st\) 集合用于存储单链表的每个结点
- 遍历单链表的每个结点
- 如果当前结点没有出现在 \(st\) 集合中,则将该结点添加到 \(st\) 集合中
- 否则,则代表该结点被重复遍历,当前结点就是环的入口结点,返回该节点
- 遍历完成,返回 \(NULL\)
/*
1.时间复杂度:O(n)
2.空间复杂度:O(n)
最坏情况下,单链表的所有结点都存入set
*/
class Solution
{
public:
ListNode *EntryNodeOfLoop(ListNode *pHead)
{
unordered_set<ListNode *> st;
while (pHead)
{
if (st.find(pHead) == st.end())
{
st.insert(pHead);
pHead = pHead->next;
}
else
{
return pHead;
}
}
return nullptr;
}
};