题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题思路
方法一:Map
1、思路:用map将所有链表结点指针保存下来,然后遍历链表,如果当前结点指针已经在map中存在,则找到链表环的入口结点,返回该结点指针,否则将该结点指针保存下来。
2、代码:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if (!pHead) return nullptr;
ListNode *cur = pHead;
map<ListNode*, ListNode*> mp;
while (cur) {
if (mp.find(cur) != mp.end()) {
return cur;
}
mp[cur] = cur;
cur = cur->next;
}
return nullptr;
}
};
3、复杂度:
时间复杂度:O(n);
空间复杂度:O(n)。
方法二:快慢指针
1、思路:设置快慢两个指针,慢指针一次走一步,快指针一次走两步。若链表中有环,则快慢指针迟早会相遇,然后统计环中结点的数目(假设为m),把两个指针重置为头结点,再让一个指针先走m步,然后两个指针同时走,直到相遇(假设走了k步),此时的指针指向的就是环的入口结点。直观的理解:前一个指针比后一个指针多走一个环的距离,所以当后一个指针走到环的入口结点时,前一个指针也刚好绕回了入口结点。
2、代码:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if (!pHead) return nullptr;
ListNode *fast = pHead;
ListNode *slow = pHead;
bool hasring = false;
//1、快慢指针判断链表中是否有环
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
hasring = true;
break;
}
}
if (!hasring) {
return nullptr;
} else {
//2、统计环中结点数目
int count = 1;
ListNode *cur = slow->next;
while (cur != slow) {
count++;
cur = cur->next;
}
//3、找到环中入口结点
slow = pHead;
for (int i = 0; i < count; i++) {
slow = slow->next;
}
fast = pHead;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return fast;
}
}
};
3、复杂度:
时间复杂度:O(n);
空间复杂度:O(1)。