【环形链表】

2023-11-11

前言

在这里插入图片描述
大家好,我是熊猫,今天我们来讲解几道有趣的链表题,希望大家可以在不断的打怪升级中提升自己的核心战斗力!


一、相交链表

  1. 相交链表

给你两个单链表的头节点 headA 和 headB ,
请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
在这里插入图片描述> 题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。

(一)题目分析

我们先来看一下题目:
题目给了两个链表,这两个链表可能有相交部分,也可能没有,
如果有:就返回相交的第一个节点,
如果没有:就返回NULL.
需要注意的一点是:我们不能改变原链表。

1、最简单的方法:暴力破解 我们直接给它套上两层循环、依次遍历每个节点,
当两个节点都遍历到空时则表明没有相交节点,否则第一个想等的节点就是第一个相交的节点(相等指的是地址相等而非数值相等)。

不过显而易见,这种方法的时间复杂度为O(n^2),空间复杂度为O(1)

2.那么我们能否将该算法化简,将时间复杂度降低呢? 在这里插入图片描述
这里我们可以先分别计算出两个链表的长度,计算它们的差值dif,
让长的链表先走dif步,之后两个链表就可以一起往前走,当两个节点相同时,我们就找到了第一个相交的节点,
当然,如果没有相交节点,两个链表最后都会指向空的。
动画演示:

相交链表--1

相交链表--2

(二)题目代码

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode LN;

struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
	int lenA = 0;
	int lenB = 0;
	LN* curA = headA;
	LN* curB = headB;
	// 说明1:下面的代码中我们两个链表都少走了一步,这是为了找到最后一个节点,
	// 如果最后一个节点都不相等,那就表明没有相交节点,我们就不要继续后面的比较操作了
	// 说明2:两个链表都少走一步,对差值无影响
	while (curA->next) // 最后都指向最后一个节点
	{
		lenA++;
		curA = curA->next;
	}
	while (curB->next)
	{
		lenB++;
		curB = curB->next;
	}

	if (curA != curB) // 如果最后一个节点地址不同,说明没有相交节点
		return NULL;

	int dif = abs(lenA - lenB); // 计算差值
	LN* longHead = headA;
	LN* shotHead = headB;
	if (lenA < lenB) // 找到长短链表
	{
		longHead = headB;
		shotHead = headA;
	}

	while (dif--) // 长链表先走差值步
	{
		longHead = longHead->next;
	}

	while (longHead != shotHead) // 之后一起走
	{
		longHead = longHead->next;
		shotHead = shotHead->next;
	}

	return longHead;
}

提交实例:
在这里插入图片描述


二、环形链表 ①

  1. 环形链表

给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
在这里插入图片描述

(一)题目分析

题目给了我们一个链表让我们判断链表中是否存在环,那么我们是否可以直接遍历一遍呢?
没有环就会遍历到NULL,那我们就可以直接返回FALSE,否则如果存在环的话就会走到重复的节点,那就返回TRUE不就好啦?
一开始肯定会有同学会这样想,但是实际上,如果不存在环的话我们很容易判断,可如果有环的话我们又怎么判断这个节点是已经走过的节点呢?我们只会在环中无限循序直至超出时间限制。

我们需要换一种解题方式,这里我们只用一个指针时肯定无法判断一个节点是否已经走过的,那么我们是否可以再增加一个指针,两个指针走的速度不同,走的快的指针先入环,走的慢的指针后入环,
之后这个题目就变成了追及与相遇问题,两个指针都在环中走,走的快的肯定可以追上走的慢的,当它们相遇时就说明存在环,否则当走的快的遇到NULL时,就说明不存在环。

循环链表--1


循环链表--2

(二)题目代码

示例:

typedef struct ListNode LN;

bool hasCycle(LN* head) {
	if (!head)
		return false;

	LN* fast = head;
	LN* slow = head;
	while (fast && fast->next)
	{
		fast = fast->next->next;
		slow = slow->next;

		if (fast == slow)
			return true;
	}

	return false;
}

提交实例:
在这里插入图片描述
上面我们写的fast速度为slow速度的两倍,其实也可以写成三倍,四倍,五倍等等,只要一个跑的快,一个跑的慢最后就都会相遇,不过跑过的圈数会有所不同。


三、环形链表 ②

  1. 环形链表 II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

(一)解法1 – 数学分析,公式推导

题目分析

在上一题我们能够确定一个链表中是否带有环,同时我们也看了相关的两个视频,
下面我们来分析一下两者的运动路程:
在这里插入图片描述

题目代码

示例:

typedef struct ListNode LN;

LN* hasCycle(LN* head) {

	LN* fast = head;
	LN* slow = head;
	while (fast && fast->next)
	{
		fast = fast->next->next;
		slow = slow->next;

		if (fast == slow)
			return fast;
	}
	return NULL;
}

LN* detectCycle(LN* head)
{
	if (!head)
		return head;

	LN* meet = hasCycle(head);
	if (!meet)  //没有环
		return meet;

    LN* cur =head;
	while (meet != cur)
	{
		meet = meet->next;
		cur = cur->next;
	}

	return meet;
}

提交实例:
在这里插入图片描述


(二)解法2 – 切断环,改变问题为相交链表

题目分析

在第二题中我们可以判断一个链表有没有带环,在第一题中我们可以找到一个两个相交链表的第一个相交节点,
说到这里我想大家已经知道我们下一步应该怎么做了吧!
我们在判断链表存在环之后可以将环从相遇点断开(新链表从相遇点开始),我们直接找相交链表的第一个相交节点即可。

视频解析:

切断循环链表

题目代码

示例:

typedef struct ListNode LN;

 LN* hasCycle(LN* head) {

 	LN* fast = head;
 	LN* slow = head;
 	while (fast && fast->next)
 	{
 		fast = fast->next->next;
 		slow = slow->next;

 		if (fast == slow)
 			return fast;
 	}
     return NULL;
 }

 LN* getIntersectionNode(LN* headA, LN* headB) {
 	int lenA = 0;
 	int lenB = 0;
 	LN* curA = headA;
 	LN* curB = headB;
 	while (curA) // 获取长度
 	{
 		lenA++;
 		curA = curA->next;
 	}
 	while (curB)
 	{
 		lenB++;
 		curB = curB->next;
 	}

 	int dif = abs(lenA - lenB); // 计算差值
 	LN* longHead = headA;
 	LN* shotHead = headB;
 	if (lenA < lenB) // 找到长短链表
 	{
 		longHead = headB;
 		shotHead = headA;
 	}

 	while (dif--) // 长链表先走差值步
 	{
 		longHead = longHead->next;
 	}

 	while (longHead != shotHead) // 之后一起走
 	{
 		longHead = longHead->next;
 		shotHead = shotHead->next;
 	}

 	return longHead;
 }

 LN* detectCycle(LN* head) {
 	if (!head)
 		return head;
 	LN* meet = hasCycle(head); // 找到一个相遇点
 	if (!meet) // 没有环就退出
 		return NULL;
 	LN* next = meet->next;
 	meet->next = NULL; //  断开环
 	meet = next; // 此时问题变成了寻找两个链表相交的问题
 	return getIntersectionNode(meet, head);

 }

提交实例:
在这里插入图片描述


(三)解法3 – 改变链表,使得每个节点自环

题目分析

这里我们提供一种“错误的方法”:
遍历链表,每次都使相应的节点的next指针指向自己(自环),如果链表不带环就会走到NULL,如果链表本身就是带环的话我们就能够回到我们设置的自环节点,并且该节点就是入环的第一个节点。
(这里之所以说是错误的方法并不是说得不到正确的结果,只是这种方法对链表改动过大,无法通过LeetCode的检测)
视频解析:

切断循环链表2

题目代码

示例:


typedef struct ListNode LN;

LN* detectCycle(LN* head) {
 	if (!head)
 		return head;

 	LN* cur = head;
 	while (cur)
 	{
 		LN* next = cur->next;
 		if (cur == next)
 			return cur;
 		cur->next = cur;
 		cur = next;
 	}

 	return NULL;
 }

运行实例:


总结

以上就是今天讲解的环形链表的全部内容,如果大家有什么疑问或者建议都可以在评论区留言,感谢大家对在这里插入图片描述的支持。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【环形链表】 的相关文章

随机推荐

  • JavaScript图像处理(5) - 曲线操作(Curve Manipulation)

    直方图均衡作为一个自动的方法虽然可以在大多数情况下获得不错的效果 但是很多时候也受限于其单一的功能而无法满足多样化的图像处理需求 尤其是在图像的艺术处理方面 直方图均衡往往并不能达到期望的效果 有时候我们需要增强图像中的高光或者是明亮的背景
  • 使用Map集合作为封装SQL查询结果的场景和注意事项

    一 使用Map集合作为封装SQL查询结果的场景 返回给前端的参数可以看做一个集合里面封装了多个对象 并且返回的字段较少 没有合适的类可以接收 这种时候可以使用Map集合进行接收参数 在XML配置文件中返回值类型可以用Map集合 使用Map集
  • AR地图微信小程序:数字化时代下地图应用的新突破

    随着数字化时代的到来 地图应用成为人们日常生活中不可或缺的工具 而随着增强现实 AR 技术的快速发展 AR地图微信小程序应运而生 为用户提供了一种全新的地图导航体验 本文将深入探讨AR地图微信小程序的专业性和思考深度 并分析其在地图应用领域
  • 有Mysql数据库的情况下为什么要用Hive数据库?

    有Mysql数据库的情况下为什么要用Hive 最近接到公司的一个需求 要求使用Hive做数据查询 当时第一反应就是What Hive是什么鬼 一脸懵逼状 请原谅一个刚开始实习的Java实习生见识短浅 然后发现了hive的一些问题 下面简单介
  • SPSS(二)SPSS实现多因素方差分析模型(图文教程+数据集)

    SPSS 二 SPSS实现多因素方差分析模型 单因素方差分析上一篇博客https blog csdn net LuYi WeiLin article details 89917656已经介绍完毕 这篇博客我们主要来学习多因素方差分析 多因素
  • 给点云添加不同类型的噪声

    1 对于点云 首先要归一化 即将点云最大值归一化为1 matlab代码如下 path which normalization path path 1 end size normalization m 2 fpath fullfile pat
  • getshell神器工具怎么用

    getshell神器工具怎么用 多线程http并发编写出来的扫描工具 速度快 稳定性高 内存占用小扫到的百分之95都是一手的 可以更好的进行安全检测 更会不定时更新exp漏洞完全打破了目前网上所有的后缀扫描方式 tg xise404演示地址
  • 第五章 循环结构程序设计 习题(后五题编程题)

    1 文字 定义整数变量i j n 0 sum i 3 判断i lt 1000值为真走4 否则输出n 结束 执行赋值 sum 0 j 1 j判断
  • [网络安全自学篇] 三十四.Windows系统安全缺陷之5次Shift漏洞启动计算机机理分析

    这是作者的系列网络安全自学教程 主要是关于安全工具和实践操作的在线笔记 特分享出来与博友们学习 希望您们喜欢 一起进步 前文详细讲解了绕狗一句话原理 绕过安全狗的常用方法和过狗菜刀 并实践安装安全狗进行实际测试 本文将分享Windows系统
  • mysql存放double_double在数据库怎么定义 如何将double数组转成二进制存到数据库里...

    double是什么数据类型 它有什么作用 怎么在MYSQL数据库的表中插入一个double型数据 我插入double型数据的时候MYSQL会直接将double型数据四舍五入为整数 如double型的没有设置小数后保留几位 执行下面msqly
  • 股票期权与定价以及用python实现

    期权是一种能在未来特定时间以特定价格买进或卖出一定数量的特定资产的权利 期权交易是一种权利的交易 在交易中 买方在支付了一笔费用 权利金 之后 获得了后约赋予的 在合约规定时间 按事先确定的价格 执行价格 向期权卖方买进或卖出一定数量期货合
  • mysql、redis、nginx等linux搭建

    mysql5 7版本搭建 1 从MySQL Download MySQL Community Server Archived Versions 选择5 7版本64位下载 一般选择5 7版本 2 将mysql压缩包放在服务器 usr loca
  • sqli-labs/Less-26a

    这一关还是提示我们空格和注释符被过滤掉了 可能还是和上一关一样 逻辑运算符也被过滤了 那么和上一关的不同之处可能就在于注入类型的不同 我们首先判断一下注入类型 先判断是否为数字型 输入如下 id 1 0b 26 26 0b1 2 回显如下
  • jquery checkbox选中事件监听

    div span 全选 全不选 span div
  • 深度解析MySQL 5.7之中文全文检索

    InnoDB默认的全文索引parser非常合适于Latin 因为Latin是通过空格来分词的 但对于像中文 日文和韩文来说 没有这样的分隔符 一个词可以由多个字来组成 所以我们需要用不同的方式来处理 在MySQL 5 7 6中我们能使用一个
  • Android InputEventReceiver事件接收流程分析

    本文基于Android 12 InputEvent经过inputflinger读取后 通过Inputchannel发送到Java层的InputEventReceiver对象 输入事件和View的状态强相关 事件发送需要确定当前的焦点App
  • (1)2D绘图详解(QPainter)

    一 Qt绘制事件 当应用程序收到绘制事件时 就会调用QWidget paintEvent 该函数就是绘制窗口的地方 有两种方法要求重绘一个窗口 1 update 把重绘事件添加到事件队列中 重复调用update 会被Qt合并为一次 不会产生
  • 【满分】【华为OD机试真题2023 JAVA&JS】区间连接器

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 区间连接器 知识点数组排序滑窗 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 有一组区间 a0 b0 a1 b1 a b 表示起点 终点 区间有可能重叠 相邻
  • 区块链+光伏产业,阻力更大还是前景更大?

    区块链通过比特币这样的形式 让世人看到了它神奇的一面 想象空间非常大 驱动了诸多领域对它的研究 这使得业内人士对于区块链 光伏产业相结合提出了疑问是阻力大还是前景更大呢 在国内现有的电力交易市场中 电力交易主要掌握在国有电网公司手里 然而
  • 【环形链表】

    目录 前言 一 相交链表 一 题目分析 二 题目代码 二 环形链表 一 题目分析 二 题目代码 三 环形链表 一 解法1 数学分析 公式推导 题目分析 题目代码 二 解法2 切断环 改变问题为相交链表 题目分析 题目代码 三 解法3 改变链