链表环的问题有两种,一种是判断是否存在环,另一种是在有的基础上返回入环的第一个节点。
简单思路:
1、遍历链表,如果遇到空,那么肯定无环。
2、在遍历的过程中,每个节点都加入到哈希表中,加入前判断是否存在,如果存在的话那么就有环,而且第一个判断存在的节点就是入环的第一个节点。
总结:这个比较简单,既可以做到第一种问题,也可以做到第二种问题。但是用到了额外空间。
下面说一下另一个思路,使用快慢指针。针对两个问题分别讨论,基本上思路都是一致的。
问题一:
思路:
1、遍历链表,如果遇到空,那么肯定无环。
2、在遍历过程中,如果快慢指针相遇那么就存在环。
总结:如果没有环肯定会因为第一个条件终止,有环就会满足第二个条件。
class Solution {
public:
bool hasCycle(ListNode *head) {
if( (head == NULL) || (head->next == NULL) ){
return false;
}
ListNode* f = head;
ListNode* s = head;
while( (f != NULL) && (f->next != NULL) ){
f = f->next->next;
s = s->next;
if( f == s ){
return true;
}
}
return false;
}
};
问题二:
思路:
和问题一相同,在问题一的基础上,如果发现有环那么快指针回到头结点,快指针变为一次走一步,再次和慢指针相遇的时候快慢指针都指向了入环的第一个节点。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if((head == NULL) || (head->next == NULL))
return NULL;
ListNode *slow = head;
ListNode *fast = head;
bool exist = false;
while((fast != NULL) && (fast->next != NULL)){
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
exist = true;
break;
}
}
if( exist ){
fast = head;
while( fast != slow ){
fast = fast->next;
slow = slow->next;
}
return fast;
}
return NULL;
}
};