网站产品推广北京百度推广优化公司
网站产品推广,北京百度推广优化公司,单位网站建设汇报材料,工程公司税率是多少难度参考 难度#xff1a;中等 分类#xff1a;链表 难度与分类由我所参与的培训课程提供#xff0c;但需要注意的是#xff0c;难度与分类仅供参考。且所在课程未提供测试平台#xff0c;故实现代码主要为自行测试的那种#xff0c;以下内容均为个人笔记#xff0c;旨在…难度参考 难度中等 分类链表 难度与分类由我所参与的培训课程提供但需要注意的是难度与分类仅供参考。且所在课程未提供测试平台故实现代码主要为自行测试的那种以下内容均为个人笔记旨在督促自己认真学习。
题目 给定一个链表返回链表开始入环的第一个节点。如果链表无环则返回u。为了表示给定链表中的环使用整数pos来表示链表尾连接到链表中的位置(索引从0开始)。如果pos是-1则在该链表中没有环。 示例1: 输入head[3,2,0,-4],pos1 输出节点2 解释链表中有一个环其尾部连接到第二个节点。 额外要求不允许修改给定的链表
思路 为了解决这个问题首先需要了解 Floyd 的循环检测算法又称为龟兔赛跑算法。该算法的核心思想是使用两个指针以不同的速度移动一个快指针通常称为 “hare”和一个慢指针通常称为 “tortoise” 或 “turtle”。“hare” 以两倍的速度移动两个节点一次而 “tortoise” 以单倍速度移动一个节点一次。 当两个指针都进入环时快指针最终会追上慢指针。这是因为每次移动时快指针都比慢指针多走一步。一旦快慢指针在环内相遇我们就可以确定链表内确实存在一个环。 接下来找出环的入口点。当快慢指针第一次相遇将快指针或慢指针重新设置到链表起点这次两个指针都以相同速度前进每次移动一个节点。当它们再次相遇的点就是环的入口。
示例 假设有以下链表 3 - 2 - 0 - -4^ || v---------- 初始化两个指针 turtle乌龟 和 hare兔子它们都指向链表的头部节点 head值为3的节点。 循环开始hare 以2步的速度移动turtle 以1步的速度移动。在第一次迭代后turtle 指向值为2的节点hare 指向值为-4的节点。 继续迭代hare 继续2步步进移动到值为2的节点因为链表有环turtle 移动1步现在指向值为0的节点。 继续迭代由于环的存在hare 和 turtle 最终在值为0的节点相遇。这意味着链表有环。 在确认链表有环之后将其中一个指针这里是 turtle移回到链表的头部然后以相同的速度每次移动一步移动两个指针当它们相遇时即为环的起点。 在这个迭代中turtle 从值为3的节点开始而 hare 从值为0的节点开始。二者都向前移动一步。在第二步中turtle 指向值为2的节点hare 也指向值为2的节点二者相遇这就是环的入口节点。
梳理 当检测到环存在时根据 Floyd 的循环检测算法我们可以确定环入口的位置。这是由以下数学逻辑得出的 让我们假设
链表头部到环入口的距离有 A 个节点环入口到乌龟和兔子的相遇点有 B 个节点相遇点回到环入口有 C 个节点 因此当乌龟和兔子在相遇点相遇时
乌龟走了 A B 步兔子走了 A B k(C B) 步其中 k 是兔子在环里跑了完整的圈数 因为兔子走得快速度是乌龟的两倍所以兔子走的步数是乌龟的两倍得到等式
2(A B) A B k(C B)通过简化等式我们得到 A k(C B) - B进一步简化得到 A C (k-1)(C B) 这个等式表示从头部到环入口的距离 A 等于相遇点到环入口的距离 C 加上 (k-1) 个环的长度 (C B)。 等式说明从链表头部到环入口的距离可以通过从相遇点继续走过 C又或者走过 C 整数倍的环长度(因为完整走过环的任何倍数你都会再次回到相同的点)。这正是 Floyd 算法中的关键部分。 因此我们可以
将一个指针重置到链表的起点。让两个指针一个从链表起点另一个从相遇点以相同的速度移动每次一步。两个指针相遇的地方就是环入口。 所以当这两个指针再次相遇时该位置就是链表的环入口节点。在前面的例子中图形化的解释就是从头节点出发到达环入口节点值2需要走两步从相遇点节点值0继续走回到环入口节点值2也正好是两步因此两个指针会在环入口节点相遇。 代码
#include iostream // 引入输入输出流库
using namespace std; // 使用标准命名空间// 链表节点定义
struct ListNode {int val; // 节点值ListNode* next; // 下一个节点指针ListNode(int x) : val(x), next(nullptr) {} // 初始化构造函数
};// 检测链表是否有环并返回环入口节点的函数
ListNode *getIntersectionNode(ListNode *head) {ListNode *turtle head; // 初始化慢指针为头部ListNode *hare head; // 初始化快指针为头部// 使用快慢指针检测环bool isCycle false; // 记录是否存在环while (hare ! nullptr hare-next ! nullptr) {turtle turtle-next; // 慢指针前进一步hare hare-next-next; // 快指针前进两步if (turtle hare) { // 若快慢指针相遇isCycle true; // 确认有环break; // 跳出循环}}if (!isCycle) {return nullptr; // 无环返回 nullptr}// 寻找环的入口turtle head; // 将慢指针重置到头部while (turtle ! hare) { // 当快慢指针不相遇turtle turtle-next; // 慢指针前进一步hare hare-next; // 快指针前进一步}return hare; // 返回环的入口节点
}// 主函数
int main() {// 创建链表并设置成环形ListNode *head new ListNode(3); // 头部节点值为3head-next new ListNode(2); // 第二个节点值为2head-next-next new ListNode(0); // 第三个节点值为0head-next-next-next new ListNode(-4); // 第四个节点值为-4// 设置环形链表指向位置 pos 1即节点值为2的节点head-next-next-next-next head-next;// 检测环入口节点ListNode *entry getIntersectionNode(head);// 如果存在环入口节点则输出否则输出 nullptrif (entry ! nullptr) {cout 节点 entry-val endl; // 存在环输出环入口节点的值} else {cout nullptr endl; // 无环的情况输出 nullptr}// 已省略删除链表节点。return 0; // 程序结束
}
打卡
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/91099.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!