前两天一直在debug,今天才有时间好好刷一下力扣,今天在代码随想录上看到环形链表,链接如下:https://leetcode.cn/problems/linked-list-cycle-ii/description/
这道题官方有两种解法,一种是相对比较简单的哈希表,还有一种是利用数学计算出他们的规律进而解题。
首先说第二种,在示例中
3 -> 2 -> 0-> 4-> ^ | <- <- <- <-
链表从3开始,依次对2 0 4 2 0 4进行遍历。如果无环返回null,有环的话求他们的环起始点。本质上这是两个问题,所以先对第一个问题求解:判断是否有环。在这里我们先设置两个指针,也就是双指针法(fast/low),然后我们fast指针每次遍历两个结点,low指针每次遍历一个结点,那么最后他们一定在环中相遇。
而后计算他们在入环中的第一个入环结点,这个我是直接看的答案,想了一会一点思路没有果断放弃 :-<(妈的看答案还得反应半天)
简单来说:设从起始结点到环起始点的距离为x,环起始点到他们在环中相遇的结点距离是y,相遇的点要走z个结点回到环起始点,具体的图如下:
那么从这图中和我们之前设置可知,slow指针共走了x+y个结点,fast指针共走了x+y+n(y+z)个结点。由于fast和slow是二倍的关系,所以可以列等式
(x + y) * 2 = x + y + n ( y + z ) x = (n - 1)(x + y) + z
n是fast在相遇前走过的圈数。然后进行化简得到第二行,这里n是需要大于等于1的,因为fast指针必须至少转1圈,否则就出现没转一圈直接和slow相遇了(这不符合常理!)综上,当n = 1时,x = z。也就是一个结点从相遇的点开始出发,另一个点从头结点开始出发,走相同的距离然后相遇。起始n不等于1也是一样,只是在环中的结点要多走几圈罢了。代码实现如下:
class Solution { public: ListNode *detectCycle(ListNode *head) { if((head == nullptr) || (head->next == nullptr)){ return nullptr; } struct ListNode* slow = head; struct ListNode* fast = head; do{ int count = 0; while((count != 2)&&(fast != NULL)){ fast = fast->next; count++; } slow = slow->next; } while((fast != slow)&&(slow != nullptr)); struct ListNode* q = fast; struct ListNode* p = head; while((p!=NULL)&&(q!=NULL)){ if(p == q){ return p; } p = p->next; q = q->next; } return nullptr; } };
代码写的过于冗余,但是还是可以看懂的。
同时还有一种方法是哈希表,虽然数据结构学过哈希表,但是并没有在C++中用过,所以写的不太熟练。
如果用哈希表的话那么就会简单很多了,下面是详细解释官方题解(因为没怎么用过)
class Solution { public: ListNode *detectCycle(ListNode *head) { // 定义一个哈希表用于存储访问过的节点 unordered_set<ListNode *> visited; // 遍历链表 while (head != nullptr) { // 如果当前节点已经在哈希表中,说明遇到了环 if (visited.count(head)) { return head; // 返回环的起点 } // 将当前节点加入哈希表 visited.insert(head); // 移动到下一个节点 head = head->next; } // 如果没有遇到环,返回 nullptr return nullptr; } };
unordered_set<ListNode > visited;
//无序集合来存链表中的结点指针,集合中每个元素都是ListNode的指针
然后需要遍历链表,每个结点在哈希表中貌似都是head结点
if (visited.count(head)) { //使用visited.count(head)检查当前结点是否在集合中, return head; //如果返回1就代表访问过了,就代表我们遇到环了, } //当前结点就是环起点。
visited.insert(head); 当前结点没访问过的话,就把此结点添加到集合中,同时移动到下个结点head = head->next;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效