原题链接: 141. 环形链表 - 力扣(Leetcode)
tag: 双指针, 链表.
一. 题目
给你一个链表的头节点 head , 判断链表中是否有环.
如果链表中有某个节点, 可以通过连续跟踪 next 指针再次到达, 则链表中存在环. 为了表示给定链表中的环, 评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 注意: pos 不作为参数进行传递 . 仅仅是为了标识链表的实际情况.
如果链表中存在环, 则返回 true . 否则, 返回 false .
二. 题解
对于本题采用 双指针 的方法, 定义慢指针 slow 指向链表的头节点 head, 定义快指针 fast 指向链表的头节点 head. 慢指针 slow 一次走一步, 快指针 fast 一次走两步.
当慢指针 slow 进环时, 快指针已经指向环中的某个节点, 从此刻开始, 快指针 fast 开始追击慢指针 slow. 由于快指针 fast 一次走两步, 慢指针 slow 一次走一步, 每循环一次该步骤快慢指针之间的距离缩小一步, 最终快指针一定会追上慢指针, 即 slow == fast , 返回 true .
若给出的链表不是环形链表, 则快指针会先抵达链表尾部, while 循环终止, 返回 false .
定义慢指针 slow, 快指针 fast.
ListNode* slow = head, * fast = head;
当 fast 和 fast->next 不为空时.
fast != nullptr && fast->next != nullptr
慢指针走一步.
slow = slow->next;
快指针走两步.
fast = fast->next->next;
slow != fast
重复这一步骤.
重复这一步骤.
slow == fast, 返回 true.
三. 复杂度分析
时间复杂度: O(N), N 是链表的长度, 快慢指针相遇前, slow 指针和 fast 指针走的次数都小于 N, 两个指针 slow , fast 走的总次数小于 2N.
空间复杂度: O(1).
四. 代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* slow = head, * fast = head; // 定义慢指针 slow, 快指针 fast
while (fast && fast->next) {
slow = slow->next; // 慢指针走一步
fast = fast->next->next; // 快指针走两步
if (slow == fast) { // 若快慢指针相遇
return true;
}
}
return false;
}
};