
解法一:哈希表法
哈希表具有唯一性。记录所有访问过的节点内存地址。
每访问一个节点,先检查其是否已存在在哈希表里。
若存在,则说明链接有环。若不存在 则继续 直到遍历至nullptr仍然无环。
cpp
/**
* 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) {
unordered_set<ListNode*> seen;//哈希表
while(head!=nullptr){
if(seen.count(head)){//先检查head这个节点是否在seen中有
return true;
}
seen.insert(head);//如果没有 那就把head放到seen中
//然后head前移
head = head->next;
}
return false;
}
};
法二 :快慢指针法 Floyd 判圈算法,面试标准答案
核心原理
利用两个速度不同的指针在链表上遍历:
- 慢指针(slow):每次移动 1 步
- 快指针(fast):每次移动 2 步
两种情况的必然性
- 链表无环 :快指针速度更快,必然先到达链表尾部(
fast == nullptr或fast->next == nullptr),两指针永远不会相遇 - 链表有环:快指针先进入环内循环,慢指针随后进入环内。由于快指针相对慢指针的速度为 1 步 / 次,两者的距离会每次缩短 1 步,最终必然在环内相遇
cpp/** * 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) { //法二 快慢指针法: //如果不是回环 快指针先走完就知道了不是了 //如果是回环 因为快指针走的快 所以快指针和慢指针肯定会相遇 //空或者单链表 肯定不是 if (head == nullptr || head->next == nullptr) { return false; } ListNode* fast = head->next; ListNode *slow = head; while(fast!=slow){ if(fast == nullptr|| fast->next == nullptr){ return false; } fast = fast->next->next; slow = slow->next; } return true; } };