📅  最后修改于: 2023-12-03 15:40:37.099000             🧑  作者: Mango
在处理链表的过程中,很可能会遇到链表中存在循环的情况。循环链表使得链表的遍历变得比较棘手,若不处理好就会导致程序陷入死循环,进而影响程序的正确性和效率。在这篇文章中,我们将探讨如何检测链表是否存在循环。
链表是数据结构中非常基础和重要的一种,如下所示:
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode
表示链表的节点,含有一个 val
变量用来存储该节点的数值,含有一个 next
指针,指向下一个节点。若 next = NULL
,则表示该节点为链表的尾节点。
最直接的办法就是采用双重循环,即针对每个节点都遍历一遍链表,看看是否有节点指向已经遍历过的节点,如果存在这种情况,则说明链表中存在循环。
代码如下:
class Solution {
public:
bool hasCycle(ListNode *head) {
if(!head || !head->next) return false;
ListNode *p = head;
while(p) {
ListNode *q = head;
while(q != p) {
if(q == p->next) return true;
q = q->next;
}
p = p->next;
}
return false;
}
};
时间复杂度:$O(n^2)$
空间复杂度:$O(1)$
用两个指针,一个走得快,一个走得慢,来判断链表中是否存在循环。这种方法很巧妙,快指针每次走两步,慢指针每次走一步,如果两个指针相遇,则说明链表中存在循环,反之则不存在。
代码如下:
class Solution {
public:
bool hasCycle(ListNode *head) {
if(!head || !head->next) return false;
ListNode *p = head, *q = head->next;
while(p != q) {
if(!q || !q->next) return false;
p = p->next;
q = q->next->next;
}
return true;
}
};
时间复杂度:$O(n)$
空间复杂度:$O(1)$
相对于第一种解法,第二种解法要更加高效。在面试中,程序员可能会被问道这个问题。因此了解上述两种方法是非常有意义的。