剑指offer 23. 链表中环的入口结点
描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
一、思路
1. 确定有环:快慢指针,快指针要是追上了慢指针,那么就是有环。
2. 确定环长度:快慢指针相遇必定是在环内。从这个节点环回,就是环的长度。
3. 确定环入口节点:first 指针从根节点前进环的长度N,然后和second节点一起走,相遇的节点就是入口节点。
总长==N+M。M是根节点到环入口节点的长度。
快指针先走N,然后和慢指针一起走,一起走了M必会相遇。于是就找到了环入口节点。
即:如果链表中环 有N个结点,指针P1在链表上向前移动N步,然后两个指针以相同的速度向前移动。
当第二个指针指向环的入口结点时,第一个指针已经围绕着环走了一圈又回到了入口结点。
画图理解问题更佳!
1.代码实现
注意越界的判断。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
if (pHead == nullptr) return pHead;
ListNode* fast = pHead, *slow = pHead;
while (1)
{
if (fast == nullptr||fast->next == nullptr) return nullptr;
slow = slow->next;
fast = fast->next->next;
if (fast == slow) break;
//cout << slow->val<<" : " << fast->val << endl;
}
//cout << fast->val << endl;
int count = 0;
fast = fast->next;
count++;
while (fast != slow)
{
fast = fast->next;
count++;
}
fast = pHead;
slow = pHead;
for (int i = 0; i < count; i++)
{
fast = fast->next;
}
while (fast != slow)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
};
一个时间复杂度的,暂时可以不优化了。