链表——环形链表I
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
判断链表是否有环最优解法是快慢指针法(龟兔赛跑算法),时间复杂度O(n),空间复杂度O(1),不需要额外的哈希表存储节点。
核心思路:
- 定义两个指针:慢指针slow(每次走一步)、快指针fast(每次走2步)
- 两个指针同时从头节点出发
- 如果链表有环,快指针最终会在环内追上慢指针(相遇)
- 如果链表无环,快指针会先走到链表末尾(fast或fast->nullptr)
代码关键点解释:
1、边界判断:空链表或只有1个节点的链表,不可能有环,直接返回false
2、循环条件:fast!=nullptr&&fast->next!=nullptr
- 快指针每次走2步,必须保证fast->next不为空,否则会访问空指针报错
3、指针移动:慢指针一步,快指针两步,保证有环时一定会相遇
4、相遇判断:只要slow==fast,说明两个指针指向同一个节点,链表有环
完整代码实现如下:
#include
using namespace std;
// 定义链表节点结构
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* slow = head;
ListNode* fast = head;
// 快指针遍历链表(必须判断 fast 和 fast->next,防止空指针访问)
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next; // 慢指针走1步
fast = fast->next->next; // 快指针走2步
// 快慢指针相遇 → 有环
if (slow == fast) {
return true;
}
}
// 快指针走到末尾 → 无环
return false;
}
};
// 测试用例
int main() {
// 构造有环链表:1->2->3->2 (环在2节点)
ListNode* n1 = new ListNode(1);
ListNode* n2 = new ListNode(2);
ListNode* n3 = new ListNode(3);
n1->next = n2;
n2->next = n3;
n3->next = n2; // 构造环
Solution sol;
cout << boolalpha << sol.hasCycle(n1) << endl; // 输出 true
// 构造无环链表:1->2->3->nullptr
ListNode* a1 = new ListNode(1);
ListNode* a2 = new ListNode(2);
a1->next = a2;
cout << sol.hasCycle(a1) << endl; // 输出 false
return 0;
}
浙公网安备 33010602011771号