题目描述:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
1. 分析
首先厘清思路:
- 判断是否有环?
- 环中有多少节点?
- 找出环的入口节点?
对于第一个问题,我们可以使用双指针解决,细节我会在代码中注释;第二个问题,可以根据第一个问题找的环中某个节点,假设环中n个节点,我们只需迭代n次就可以让指针相遇,进而知道有多少节点数;第三个问题,我们还是利用双指针,不过第一个指针比第二个指针先走了 n 个节点(环中节点个数),这样,两个指针第一次相遇即是入口节点。
2. 用C++写出逻辑:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
ListNode* meetNode = MeetingNodeSearch(pHead);
if(meetNode == nullptr) // 没有环,直接退出
return nullptr;
int nodesInLoop = 1; // 计算环中节点个数
ListNode* p1 = meetNode;
while(p1 -> next != meetNode){
p1 = p1 -> next;
nodesInLoop++;
}
ListNode* p11 = pHead;
ListNode* p12 = pHead;
for(int i = 0; i < nodesInLoop; i++){ // 先让指针1 先走n步
p11 = p11 -> next;
}
while(p11 != p12){
p11 = p11 -> next;
p12 = p12 -> next;
}
return p11;
}
ListNode* MeetingNodeSearch(ListNode* pHead) {
if(pHead == nullptr) // 判断头节点
return nullptr;
ListNode* slow = pHead -> next;
if(!slow) // 判断是否只有一个节点
return nullptr;
ListNode* fast = slow -> next;
// 注意这里,根据下面的循环,一进去就是判断是否相等,所以我们要在进入循环之前就让快指针快一步,细节!
while(fast != nullptr && slow != nullptr){
if(slow == fast)
return slow;
slow = slow -> next;
fast = fast -> next -> next;
}
return nullptr;
}
};