141.环形链表

🍩 141.环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

img

思路

基本思想

如果链表中存在环,那么遍历之后一定会回到遍历过的位置,这里可以采用多种方式,遍历过得节点打上标记,一旦遍历到有标记的节点,那么就说明有环

本文中采用快慢指针的方式,快指针一次走两步,慢指针一次走一步,如果存在环,快指针总会追上慢指针,也就是说当快慢指针相遇,则说明有环,当便利的过程中走到了链表的尾部,说明无环,具体的判断逻辑为:

1
2
3
4
5
6
7
8
ListNode* fast=head->next;
ListNode* slow=head;
while(fast!=nullptr&&fast->next!=nullptr){
    if(fast==slow)  
        return true;
    fast=fast->next->next;
    slow=slow->next;
}

需要注意的是fast!=nullptr&&fast->next!=nullptr缺一不可,fast!=nullptr是保证了fast->next的存在,并且其至少为nullptr,此时才能有fast->next的语句出现,不会出现空指针异常的情况

fast->next!=nullptr是为了保证fast->next->next的存在,并且至少为nullptr,不会出现空指针异常

并且fast!=nullptr需要出现在fast->next!=nullptr的前面。先确保fast->next的存在

执行流程

  1. 去除空链表和只有一个节点的情况
  2. 定义快慢指针
  3. 循环遍历,查看快慢指针是否相遇

代码

根据以上分析,得出以下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution {
public:
//使用快慢指针的方法,快指针一次走两步,慢指针一次走一步
//如果有环,那么快慢指针一定会相遇
    bool hasCycle(ListNode *head) {
        if(head==nullptr||head->next==nullptr)
            return false;
        ListNode* fast=head->next;
        ListNode* slow=head;
        while(fast!=nullptr&&fast->next!=nullptr){
            if(fast==slow)  
                return true;
            fast=fast->next->next;
            slow=slow->next;
        }
        return false;
    }
};

总结

主要是知道快慢指针的原理,并且明白fast!=nullptr&&fast->next!=nullptr缺一不可,并且出现的前后顺序不能改变