当前位置: 首页 > news >正文

完整教程:数据结构:单链表的应用(力扣算法题)第二章

完整教程:数据结构:单链表的应用(力扣算法题)第二章

每题代码汇总:登录 - Gitee.com

上一章回顾:数据结构:单链表的应用(力扣算法题)第一章-CSDN博客

1.相交链表

160. 相交链表 - 力扣(LeetCode)

理解题意:

思路:

分别遍历两条单链表的长度,两条单链表长度相减,得到长度差的绝对值,让长一些的链表往前遍历长度差个结点,再让两条链表同步遍历,找相同结点。

注意:此处相同是指地址相同而不是值相同。

代码见下:

typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
//求链表长度
ListNode* pa = headA;
ListNode* pb = headB;
int sizeA = 0, sizeB = 0;
while(pa)
{
++sizeA;
pa = pa->next;
}
while(pb)
{
++sizeB;
pb = pb->next;
}
//求链表长度差
int gap = abs(sizeA - sizeB);//得到的是绝对值
//定义长短链表
//假设
ListNode* shortlist = headA;
ListNode* longlist = headB;
if(sizeA > sizeB)
{
longlist = headA;
shortlist = headB;
}
//长链表往前遍历
while(gap--)
{
longlist = longlist->next;
}
//两链表一起走
while(shortlist && longlist)
{
if(shortlist == longlist)
{
return shortlist;
}
shortlist = shortlist->next;
longlist = longlist->next;
}
//不相交
return NULL;
}

最终通过测试。

注意:

2.环形链表

141. 环形链表 - 力扣(LeetCode)

理解题意:

思路一:

使用快慢指针,慢指针一次走一步,快指针一次走两步,如果快指针和慢指针指向同一个结点,说明链表带环。

代码见下:

typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
ListNode* slow = head;
ListNode* fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
return true;
}
}
return false;
}

最终通过测试。

证明一:

证明为什么快指针每次走两步,慢指针每次走一步就可以相遇?

当slow刚入环时,其与fast的距离最远,假设为N,那么当slow走一步,fast走两步时,距离变为N-1,以此类推,最终N == 0。

证明二:

当快指针每次走3步,走4步……还能满足条件吗?

以每次走三步为例,并且需要对N进行分类讨论:

此时可以得到永远不能相遇的条件:N为奇数,C为偶数。那么,此条件正确吗?

此处假设环的周长为C,头结点到slow结点的长度为L。并且此时fast指针已经环绕X周。

依旧沿用上面的条件:3 * 慢指针路程 == 快指针路程

在追逐过程中,快慢指针所走过的路径长度:

fast:L + xC + C - N

slow:L

此时建立方程式:3L == L + xC + C - N

得:2L == (x+1)C - N,此时分两种情况:

情况1:偶数 = 偶数 - 偶数

情况2:偶数 = 奇数 - 奇数

此时可以证明上述得到的结论:N为奇数,C为偶数 不成立,则当快指针每次走3步,走4步……时,两指针依旧会相遇。

思路二:

使用快慢指针,快指针走3,4,5……步

代码如下:

typedef struct ListNode ListNode;
bool hasCycle(struct ListNode* head) {
ListNode *slow, *fast;
slow = fast = head;
while (fast && fast->next) {
slow = slow->next;
int n = 4; // fast每次⾛三,四……步
while (n--) {
if (fast->next)
fast = fast->next;
else
return false;
}
if (slow == fast) {
return true;
}
}
return false;
}

最终测试通过。

总结:虽然已经证明了快指针不论走多少步都可以满足在带环链表中相遇,但是在编写代码的时候 会有额外的步骤引入,涉及到快慢指针的算法题中通常习惯使用慢指针走⼀步快指针走两步的方式。

3.环形链表II

142. 环形链表 II - 力扣(LeetCode)

理解题意:

思路:

使用快慢指针,在环里一定会有相遇点,此时:相遇点到入环结点的距离 == 头结点到入环结点的距离。

代码如下:

typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
//创建快慢指针
ListNode* slow = head;
ListNode* fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
//相遇点:使用curr == slow,不动head,且使curr与slow一样每次走一步
ListNode* curr = head;
while(curr != slow)
{
curr = curr->next;
slow = slow->next;
}
//入环第一个结点
return curr;
}
}
//不带环
return NULL;
}

最终测试通过。

证明:

为什么在带环链表中,快慢指针相遇点到入环结点的距离 == 头结点到入环结点的距离?

此处,E为入环结点,M为相遇点,R为周长,L为头结点到入环结点的距离。

快慢指针在相遇点走的总路程:

slow = L + X

fast = L + X + nR,nR为fast指针的路程。

因为:2 * slow = fast

则:L = nR - X

L = (n - 1)R + R - X   ,其中,L为头结点到入环结点的距离,R-X为相遇点到入环结点的距离。此时,(n-1)R可省略,不影响结果。

本章完。

http://www.rkmt.cn/news/8270.html

相关文章:

  • CF2039E Shohag Loves Inversions
  • 深入解析:sqlite3的加解密全过程
  • U522155 板垣 カノエ is WATCHING YOU std
  • ctfshow web
  • 代码随想录算法训练营第三天 | leetcode 203 707 206
  • 【F#学习】数组:Array
  • ctfshow 菜狗杯
  • 详细介绍:测试用例详解
  • conda 无法安装依赖 CondaHTTPError: HTTP 000 CONNECTION FAILED for url: tsinghua tencentaliyun
  • vulnhub(持续更新)
  • 小爱同学连接电脑进行交互 教程
  • 已完成今日求所有满足长为 $a$ 的和为 $b$ 的按位或为 $c$ 的非负整数序列的异或和的异或和大学习
  • 集群无法启动CRS-4124: Oracle High Availability Services startup failed - 指南
  • Hello Yqc!
  • SAPO去中心化训练:多节点协作让LLM训练效率提升94%
  • 区间问题
  • 解决 Ubuntu 25.04 下 make menuconfig 报 ncurses 错误的问题 - 指南
  • web359
  • 如何在后端优雅地生成并传递动态错误提示?
  • web358
  • WPF包
  • 实用指南:目标检测如何将同时有方形框和旋转框的json/xml标注转为txt格式
  • ctfshow web351
  • Linux虚拟机常用命令与Hadoop生态组件启动大全
  • private void Form1_Load与构造方法前执行顺序
  • HarmonyOS Stage模型与ArkTS:现代应用开发的核心架构与最佳实践 - 详解
  • 完整教程:构建基石:Transformer架构
  • 【先记录一下】windows下使用的lazarus/fpc安装到中文的目录时出错的问题
  • CF182C Optimal Sum
  • HTB UNIV CTF 24 Armaxix靶场漏洞链:命令注入与账户接管实战