题目描述
判断链表是否有环,找到环的入口结点,如果没有环 返回Null
题目解析
- 使用set,如果不在set中,那么加入set中,返回第一个已经在set中的节点。
ListNode* LoopEntry(ListNode *head)
{
if(head == nullptr || head->next==nullptr) return nullptr;
std::set<ListNode*> st;
ListNode *cur = head;
while(cur != nullptr)
{
//第一次发现set中存在 就返回
if(st.count(cur))
{
return cur;
}
st.insert(cur);
cur = cur->next;
}
return nullptr;
}
- 使用快慢指针解决:
假设快慢指针在棕色部分相遇:此时
slow 的路程长度 = a + b
fast 的路程长度 = a + b + n(b+c), 这里的n指的是快指针可能已经在环中转了n圈了。
由于fast指针的速度是slow指针速度的2倍,那么,相同时间内,路程自然也是slow的二倍了:
2(a + b) = a+(n+1)b + nc
,化解以后,a = (n-1)(b+c)+c
如果n1,ac,即,无论n是多少,a和c是相等的
如果n==2, a == b +2c
前面推导出,a == c,当我们的快慢指针相遇后,我们定义一个指针P,每次也是走一步,那么p和slow终会相遇,相遇点就是我们环的入口。
ListNode* LoopEntry(ListNode*head)
{
if(head == nullptr || head->next==nullptr) return nullptr;
ListNode * slow = head;
ListNode * fast = head->next;
while (fast !=nullptr && fast->next != nullptr)
{
if(fast == slow)
{
//当确定有环时,定义一个从头开始走的指针,步子大小与slow一致
ListNode * p = head;
while(p != slow)
{
p=p->next;
slow = slow->next;
}
return p;
}
fast = fast->next->next;
slow = slow->next;
}
return nullptr;
}