##方法一 使用set 笔试做法
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
set<ListNode*>st;
while (head) {
if (st.find(head) == st.end()) {
st.insert(head);
head = head->next;
}
else {
return head;
}
}
return NULL;
}
};
解题思路
既然链表可能有环,即交点的地方就是重复节点的地方,将链表中的所有节点先查询是否在set中,若不存在则将元素插入,若存在说明遇到环的交点,返回即可。时间复杂度为O(N),空间复杂度也是O(N)
方法二 快慢指针 面试做法
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
if (head == NULL || head->next == NULL || head->next->next == NULL) {
return NULL;
}
fast = fast->next->next;
slow = slow->next;
while (fast!=NULL && fast != slow) {
if (fast->next==NULL||fast->next->next == NULL) {
return NULL;
}
fast = fast->next->next;
slow = slow->next;
}
if (fast == NULL) {
return NULL;
}
if (fast == slow) {
fast = head;
while (fast != slow) {
fast = fast->next;
slow = slow->next;
}
return fast;
}
return NULL;
}
};
解题思路
设置一个快指针一个慢指针,都从头节点出发,如果无环,那么快指针必然先遍历完链表,若遇到NULL,则说明无环;若两个指针相遇,即快指针从环上再次遇到慢指针,说明有环。
此时快指针返回链表头节点,慢指针原地不动,每个指针都恢复单步运行,则下一次相遇时,即为链表的入环点
代码细节
有快指针的时候,必须要判断是否越界,不能一味得向前遍历,要在适当的位置判断是否为null
因为需要分为两个大类来处理,即能不能追上,所以快慢指针向后遍历的过程中,检查两个条件,一个是fast是否到达边界;另一个是快慢指针是否相遇,若fast到达边界或者快慢指针相等则退出循环,换言之fast没到达边界并且快慢指针不相等就执行循环,两个指针不断向后移动。而且在遍历的过程中。fast的next和next的next都有可能为空,所以移动的时候都该进行判断,若为空也说明没有环。
退出循环以后就是单独处理上面可能引起退出循环的两种情况。