题目:
思路:
1.在头节点定义两个快慢指针,快指针走两个节点,慢指针走一个节点。如果快指针走的节点数过大就可能会跳过慢指针两个就不会相遇了,这个追及相遇问题跟现实的追击相遇不一样,因为快指针相当于是跳跃走的,只在最后的目的点停下至于中间的节点不算的,要搞明白。
2.找到快慢指针相遇的地方
3.再定义两个搜索节点,index2从头节点head开始,index1从fast开始。两个节点相遇的地方就是循环入口
代码:
#include <bits/stdc++.h>
using namespace std;
typedef struct ListNode{
int val;
struct ListNode *next;
}ListNode;
ListNode *detectCycle(ListNode *head){
ListNode *fast=head;
ListNode *slow=head;
while(fast!=NULL&&fast->next!=NULL){
fast=fast->next->next;//快指针走两个节点,如果走三个节点可能会跳过慢指针
slow=slow->next;//慢指针走一个节点
//快慢指针相遇
if(fast==slow){
ListNode *index1=fast;
ListNode *index2=head;//定义一个搜索指针从头节点开始
while(index1!=index2){
index1=index1->next;
index2=index2->next;
}
return index2;
}
// return NULL;
}
}
int main() {
// 构建链表 1 -> 3 -> 5
ListNode *head = (ListNode *)malloc(sizeof(ListNode));
head->val = 1;
head->next = (ListNode *)malloc(sizeof(ListNode));
head->next->val = 3;
head->next->next = (ListNode *)malloc(sizeof(ListNode));
head->next->next->val = 5;
head->next->next->next = NULL;
// 将链表变为环形链表,例如让节点 5 的下一个节点指向节点 3
head->next->next->next = head->next;
// 寻找并打印相交节点
// ListNode *intersection = getIntersectionNode(head1, head2);
ListNode *intersection = detectCycle(head);
if (intersection != nullptr) {
cout << intersection->val << endl;
} else {
cout << "-1" << endl;
}
// 断开环,避免无限循环
ListNode *temp = intersection->next;
intersection->next = NULL;
// 释放链表占用的内存
while (head != nullptr) {
temp = head;
head = head->next;
free(temp);
}
return 0;
}
小结
区分节点的相遇追击和现实的追击问题的区别,这个追及相遇问题跟现实的追击相遇不一样,因为快指针相当于是跳跃走的,只在最后的目的点停下至于中间的节点不算的。
定义:一个链表中存在一个节点,其 next
指针指向链表中的另一个节点,形成一个环。
特点:
- 链表可以是有环的或无环的(线性)。
- 如果存在环,至少有一个节点的
next
指针指向环内的另一个节点。
解题技巧:
- 快慢指针法(弗洛伊德算法):使用两个指针,一个每次移动一步(慢指针),另一个每次移动两步(快指针)。如果存在环,快指针最终会追上慢指针。
- 哈希表法:遍历链表,将节点存储在哈希表中,如果再次遇到已存储的节点,则存在环。