<p align="center">
<a href="https://www.programmercarl.com/xunlian/xunlianying.html" target="_blank">
  <img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="./qita/join.md">参与本项目</a>，贡献其他语言版本的代码，拥抱开源，让更多学习算法的小伙伴们受益！</strong></p>


# 141. 环形链表

[力扣题目链接](https://leetcode.cn/problems/linked-list-cycle/submissions/)

给定一个链表，判断链表中是否有环。

如果链表中有某个节点，可以通过连续跟踪 next 指针再次到达，则链表中存在环。 为了表示给定链表中的环，我们使用整数 pos 来表示链表尾连接到链表中的位置（索引从 0 开始）。 如果 pos 是 -1，则在该链表中没有环。注意：pos 不作为参数进行传递，仅仅是为了标识链表的实际情况。

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

![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210727173600.png)

## 思路

可以使用快慢指针法，  分别定义 fast 和 slow指针，从头结点出发，fast指针每次移动两个节点，slow指针每次移动一个节点，如果 fast 和 slow指针在途中相遇 ，说明这个链表有环。

为什么fast 走两个节点，slow走一个节点，有环的话，一定会在环内相遇呢，而不是永远的错开呢？

首先第一点： **fast指针一定先进入环中，如果fast 指针和slow指针相遇的话，一定是在环中相遇，这是毋庸置疑的。**

那么来看一下，**为什么fast指针和slow指针一定会相遇呢？**

可以画一个环，然后让 fast指针在任意一个节点开始追赶slow指针。

会发现最终都是这种情况， 如下图：

<img src='https://code-thinking.cdn.bcebos.com/pics/142环形链表1.png' width=600> </img></div>

fast和slow各自再走一步， fast和slow就相遇了

这是因为fast是走两步，slow是走一步，**其实相对于slow来说，fast是一个节点一个节点的靠近slow的**，所以fast一定可以和slow重合。

动画如下：


![141.环形链表](https://code-thinking.cdn.bcebos.com/gifs/141.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.gif)


C++代码如下

```CPP
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != NULL && fast->next != NULL) {
            slow = slow->next;
            fast = fast->next->next;
            // 快慢指针相遇，说明有环
            if (slow == fast) return true;
        }
        return false;
    }
};
```

## 扩展

做完这道题目，可以在做做[142.环形链表II](https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html)，不仅仅要找环，还要找环的入口。



## 其他语言版本

### Java:

```java
public class Solution {
    public boolean hasCycle(ListNode head) {
		ListNode fast = head;
		ListNode slow = head;
		// 空链表、单节点链表一定不会有环
		while (fast != null && fast.next != null) {
			fast = fast.next.next; // 快指针，一次移动两步
			slow = slow.next;      // 慢指针，一次移动一步
			if (fast == slow) {   // 快慢指针相遇，表明有环
				return true;
			}
		}
		return false; // 正常走到链表末尾，表明没有环
    }
}
```

### Python:

```python
class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if not head: return False
        slow, fast = head, head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if fast == slow:
                return True
        return False
```

### Go:

```go
func hasCycle(head *ListNode) bool {
    if head==nil{
        return false
    } //空链表一定不会有环
    fast:=head
    slow:=head //快慢指针
    for fast.Next!=nil&&fast.Next.Next!=nil{
        fast=fast.Next.Next
        slow=slow.Next
        if fast==slow{
            return true  //快慢指针相遇则有环
        }
    }
    return false
}
```

### JavaScript:

```js
var hasCycle = function(head) {
    let fast = head;
    let slow = head;
    // 空链表、单节点链表一定不会有环
    while(fast != null && fast.next != null){
        fast = fast.next.next; // 快指针，一次移动两步
        slow = slow.next; // 慢指针，一次移动一步
        if(fast === slow) return true; // 快慢指针相遇，表明有环
    }
    return false; // 正常走到链表末尾，表明没有环
};
```

### TypeScript:

```typescript
function hasCycle(head: ListNode | null): boolean {
    let slowNode: ListNode | null = head,
        fastNode: ListNode | null = head;
    while (fastNode !== null && fastNode.next !== null) {
        slowNode = slowNode!.next;
        fastNode = fastNode.next.next;
        if (slowNode === fastNode) return true;
    }
    return false;
};
```





<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
  <img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>
