链表算法题(OJ刷题超详细讲解)

1.返回倒数第K个节点,

OJ链接:返回倒数第K个节点

本题有很多种解法,例如创建数组,或者将原链表反转等等,这里们使用快慢指针,只需要遍历一遍链表,并且空间复杂度为O(1),时间复杂度为O(N)

我们先来画图分析一下 

我们让快指针fast先走k步,然后再一起走,最后返回slow的值。

代码如下:

typedef struct ListNode ListNode;int kthToLast(struct ListNode* head, int k){assert(head);ListNode*slow = head;ListNode*fast = head;while(k--){fast = fast->next;}while(fast){fast = fast->next;slow = slow->next;}return slow->val;}

2.链表的回文结构

OJ链接:链表的回文结构

本题要求时间复杂度为O(n),额外空间复杂度为O(1),该怎么写呢?

分析:

我们要想证明它是个回文结构,首先我们要先知道回文结构是什么,从前往后和从后往前是完全相同的,以中间节点为中心这个链表是对称的,举个例子比如12321和1221这两个都是回文,如果是123123这个还是回文吗?这种就不是回文了,如果需要证明这个链表是回文,那么我们是不是就可以先找到中间节点,然后再反转一下中间节点及之后的节点,如上图我们找到中间节点2之后把中间节点及之后的节点都反转了,然后让中间节点与首节点进行判断值是否相等,万一是奇数个节点呢,奇数个也没事我们左边的2并没有改变它的next所以2指向的还是3,3和3自己比,最后3指向的就是NULL了。

代码如下:

//找中间节点
struct ListNode* middleNode(ListNode* head)
{struct ListNode* slow = head,*fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;
}
//反转
struct ListNode *reverseList(ListNode *head)
{struct ListNode *cur = head;struct ListNode* newhead = NULL;while(cur){struct ListNode*next = cur->next;cur->next = newhead;newhead = cur;cur = next;}return newhead;
}bool chkPalindrome(ListNode* A) {// write code herestruct ListNode*mid = middleNode(A);struct ListNode*rmid = reverseList(mid);while(rmid && A){if(A->val != rmid->val)return false;A = A->next;rmid = rmid->next;}return true;
}
};

3.相交链表

OJ链接:相交链表

判断链表是否相交,如果说我们一个一个比较的话,A链表的节点依次跟B链表所有节点比较,A某个节点跟B某个节点相等,这个节点就是交点,这样太麻烦了,而且时间复杂度为O(N^2),那么我们可以先遍历链表,判断两个链表的尾节点是否相等,如果相等那么就一定相交,在我们遍历链表的时候,我们可以顺便计算出链表的相对值,然后让长的链表先走差值的距离,在同时走,只要两个节点相等就是相交

画图演示:

代码如下:

 typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {ListNode*curA = headA,*curB = headB;int lenA = 1,lenB = 1;while(curA->next){curA = curA->next;++lenA;}while(curB->next){curB = curB->next;++lenB;}//尾节点不相等就是不相交if(curA->next != curB->next){return NULL;}//长的先走差距步,在同时走,第一个相等就是相交//假设法int gap = abs(lenA-lenB);//求绝对值ListNode* longList = headA,*shortList = headB;if(lenB > lenA){longList = headB;shortList = headA;}while(gap--){longList = longList->next;}while(longList != shortList){longList = longList->next;shortList = shortList->next;}return shortList;
}

如上代码中我们用到了假设法,如果我们假设错了,就修正一下,A长还是B我们不关注,我们只要知道longList是长的shortList是短的就行,假设法可以使得我们逻辑变得更加简单。

注:我们一定要用地址进行判断,如果用值判断可能会有重复的值


4.随机链表的复制

OJ链接:随机链表的复制

深拷贝就是拷贝一个值和指针指向跟当前链表一模一样的链表

这道链表题每个节点里多了个指针指向随机节点,也有可能指向空,然后深拷贝一份,如果我们直接遍历然后拷贝呢?硬拷贝是可以的,但是有个问题,随机指针(random)指向的值如何在新链表中实现呢,如果我们去链表中查找,那么万一有重复的值怎么办呢,这就会导致没拷贝成功,如果真要用这种暴力查找,就要算相对位置,而且它的时间复杂度为O(N^2)。

我们可以先拷贝链表,然后把拷贝的链表插入到原节点的后面,每个拷贝节点和原节点建立了一个关联关系

然后我们在控制random,如下图所示,我们7的random指向的为空,那么我们拷贝节点7的random也要指向空,我们拷贝节点7就在原节点的后面,所以处理起来很方便,那么13的random指向的是7我们如何拷贝呢,拷贝节点的random指向的就是cur->random->next,最后再将拷贝节点拿下来尾插,成为一个新的链表,虽然我们破坏了原链表的结构,我们可以选择恢复原链表也可以不恢复,题目没有要求。

代码如下:

typedef struct Node Node;
struct Node* copyRandomList(struct Node* head) {Node* cur = head;// 拷贝节点插入在原节点后面while(cur){Node* copy = (Node*)malloc(sizeof(Node));copy->val = cur->val;copy->next = cur->next;cur->next = copy;cur = copy->next;}//控制randomcur = head;while(cur){Node*copy = cur->next;if(cur->random == NULL){copy->random = NULL;}else{copy->random = cur->random->next;}cur = copy->next;}//拷贝节点取下来尾插成为新链表,然后恢复原链表(不恢复也可以)Node *copyhead = NULL,*copytail = NULL;cur = head;while(cur){Node*copy = cur->next;Node*next = copy->next;if(copytail == NULL){copyhead = copytail = copy;}else{copytail->next = copy;copytail = copytail->next;}//恢复原链表cur->next = next;cur = next;}return copyhead;
}

5.环形链表

OJ链接:环形链表

思路:快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。

画图演示:

 代码如下:

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

在面试中面试官可能会问的两个问题,如下

1.为什么一定会相遇,没有可能会错过,永远追不上?请证明 

证明:假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可 能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动 一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在满指针走到一圈之前, 快指针肯定是可以追上慢指针的,即相遇

2.slow一次走一步,fast走3步4步5步n步能追上吗?请证明

证明如下:

这里我们假设fast一次走3步,当slow进环时,fast开始追击slow,过程中距离变化如下:

偶数                        奇数

N                              N

N-2                           N-2

N-4                           N-4

....                             ....

4                                3

2                                1

1                                -1

0                

每追击一次,距离缩小2

0就是追上了

追成-1就是刚好错过,开始新一轮的追击了

距离变成C-1,(假设C是环的长度)

总结一下:

1、N是偶数,第一轮就追上了

2、N是奇数,第一轮追击会错过,距离变成C-1

        a、如果C-1是偶数,下一轮就追上了

        b、如果C-1是奇数,那么就永远追不上

我们在来分析一下会不会出现永远追不上的可能,上面的b条件成不成立呢?

永远追不上是有条件的,同时存在N是奇数且C是偶数,那么就永远追不上

那么有没有可能这两个条件不存在?证明一下

证明如下:

假设slow进环时,fast跟slow距离是N

slow走的距离是L

fast走的距离:L+x*C+C-N

slow进环时,假设fast已经在环里转了x圈

fast走的距离是slow的3倍

3*L= L+x*C+C-N

化简一下变成:2*L = (x+1)*C-N

偶数 = (x+1)*偶数-奇数

N是奇数时,C也是奇数

N是偶数时,C也是偶数

只有奇数-奇数才能变成偶数

(x+1)*偶数一定是偶数

所以N是奇数且C的偶数不能同时存在,永远追不上的条件不成立

结论:

N是偶数,第一轮就追上了

N是奇数,第一轮追不上,C-1是偶数第二轮就追上


6.环形链表II

OJ链接:环形链表II

我们依旧可以使用快慢指针,slow走一步fast走两步,当它们在环里相遇时,让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行, 两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。

在我们面试的时候面试官可能会问这样的问题,为什么它们最终肯定会在入口点的位置相遇呢?请证明一下?

证明如下:

假设入环前的这段距离是L

假设相遇点到入环点的距离是N

长的环度是C

假设x是fast在环里转了x圈(x>=1)

相遇时:

slow走的路程:L+N

fast走的路程:L+x*C+N

fast走的路程是slow2倍

2*(L+N)=L+x*C+N

L+N = x*C

L=x*C-N

最终化简成这样:L=(x-1)*C+C-N

假如x=1,那么L=C-N,正好是相遇点到进环点的距离与入环之前的距离相等,让一个节点从头开始遍历,一个从相遇点开始,最终在入环的第一个节点相遇,证明了我们肯定会在入口点的位置相遇,如果x不唯1呢,那也会相遇,无非就是在环里多走了几圈,最后还是会在入环的第一个节点相遇

代码如下:

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode*slow=head,*fase = head;while(fase && fase->next){slow = slow->next;fase = fase->next->next;//相遇if(slow == fase){struct ListNode*meet = slow;while(meet != head){meet = meet->next;head = head->next;}return meet;}}return NULL;
}

总结

经过这次对链表算法题的深入解析,链表作为基础数据结构,其相关算法是编程能力的试金石。通过在线刷题平台,我们可以不断挑战自我,深化对链表的理解,提高算法设计能力。

刷题能够让我们更加熟悉各种算法和数据结构,掌握它们的基本操作和应用场景。通过大量的实践,我们能够加深对理论知识的理解,形成自己的编程风格和思维方式。

刷题不是目的,应用才是关键。让我们通过刷题,不断提升编程水平,将所学知识应用于实际项目中,成为更优秀的开发者。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/21622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

选择困难!?伦敦金etf谁胜一筹?

虽然伦敦金和黄金ETF都是黄金的投资方式,但它们有着许多不一样的地方。伦敦金市场是全球最大的黄金市场之一,每天的交易量巨大,没有任何财团或机构能够人为操控它,而且整个市场24小时公开地运行,投资者可以灵活把握市场…

HCIP-RS实验-OSPF单区域配置

目录 简介:建立新拓扑配置IP验证IP连通性配置单区域的OSPF查看网络连通性查看路由器运行的基本OSPF信息查看路由器的OSPF邻居关系建立情况查看路由器的OSPF数据库信息。 观察路由器在以太网上邻接关系的建立过程 简介: OSPF(Open Shortest P…

在C#中使用 NLog 库进行日志记录

NLog 是 .NET 的日志记录框架。具有丰富的日志路由和管理能力,极大地帮助您生成和管理日志。NLog 是一个库,可以轻松地同时记录和管理多个不同区域(例如控制台、数据库或文本文件)中的数据。我们可以按如下方式列出 NLog 的功能&a…

云服务训练YOLOv8-训练改进

迪菲赫尔曼录制的视频 准备工作: 1、安装VSCode, 2、安装VSCode插件, Remote-SSH、Chinese(Simplified) 3、注册AutoDL账号 AutoDL算力云 4、上传数据集: 训练集 验证机 测试集 5、租服务器 6、连接服务器 7、下载代码…

天数智芯的天垓150 GUP性能及应用

天数智芯的天垓150是一款高性能的通用GPU训练产品,其性能特点及应用场景可以清晰归纳如下: 性能特点 高度兼容性: 天垓150采用通用GPU架构,兼容国际主流GPU通用计算模型,确保与各种主流系统和应用的顺畅集成。广泛支…

家庭服务器

以下是一些您可以使用家庭服务器的方式: 家庭自动化任务:您可以使用家庭服务器来运行自动化任务,例如控制智能家居设备、定时备份数据、监控家庭网络等。 游戏服务器:如果您是游戏爱好者,您可以在家庭服务器上托管游戏…

Android R及以上版本中APP外部存储实现

背景: 从 Android R开始,Google 引入了一些新的限制,以增强用户数据的隐私保护。其中之一是对外部存储的访问限制。如果APP的target>30,之前的WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE授权方案就完全不能使用了。本文将说明如何在 …

实战攻防:蜜罐无关,溯源有术

前言 突然接到通知,甲方在HVV防守前突然收到内网IP地址出现Socks代理通信,审计流量发现确实属于socks流量,不属于告警流量,告警地址为个人终端,直接准入工具阻断等待排查。 态感告警 流量分析属于正常的socks流量。 …

【leetcode--O(1) 时间插入、删除和获取随机元素】

这道题要求实现一个类,满足插入、删除和获取随机元素操作的平均时间复杂度为 O(1)。 变长数组可以在 O(1) 的时间内完成获取随机元素操作,但是由于无法在 O(1)的时间内判断元素是否存在,因此不能在 O(1) 的时间内完成插入和删除操作。哈希表…

unify llm 大模型路由

Unify介绍 Unify是llm大模型路由框架。 Unify Python 包提供了对 Unify REST API 的访问,允许您从任何 Python 3.7.1 应用程序中查询大型语言模型(LLMs)。它包括了同步和异步客户端,并支持流式响应。 就像 REST API 一样&#…

【光伏预测】基于BP神经网络实现光伏发电功率预测附Matlab代码

matlab % 步骤1:加载光伏发电功率数据 load(‘solar_power_data.mat’); % 假设数据存储在变量power_data中 % 步骤2:数据预处理 % 将数据归一化到[-1, 1]的范围 minPower min(power_data); maxPower max(power_data); normalizedData (power_data …

职场思考-职场第三年规划重点(14)

(职场第三年规划重点(上)) 确定方向,拉进关系,提高思维 好的职业生涯规划必须具备以下三个特点: 合理性(以当事人的天赋、性格和现有知识与技能为基础,是适合并为当事人所接受的)、可…

根据用户显式内容——静态web网站与动态web网站

根据用户显式变化的内容 就像企业的Web网站一样,无论浏览网站的用户是谁,在什么时候访问,总是显式相同内容,这样的网站被称为静态Web网站;与此相对,用户发帖,不同人登录后显式不同内容的网站被称为…

vscode 如何debug(二)

在 Python 项目中配置 VS Code 进行远程调试是一个常见的需求。以下是详细的步骤,确保你可以顺利配置并进行调试: 1. 安装 DebugPy 首先,通过 pip 安装 debugpy: pip install debugpy -U2. 安装 VS Code 插件 确保你已经在 VS…

word-简历排版

1、确认字体(微软雅黑)、字号(五号/小五) 2、设置段间距和行间距、页边距 3、突出各模块标题,增加分格线 4、使用制表位进行对齐:视图-标尺,制表符(tab)和制表位共同使…

西贝柳斯终极版2023:Mac上的简易音乐记谱神器,谱写未来

Avid Sibelius Ultimate 2023 for Mac是一款专为Mac用户设计的音乐记谱软件,它以其强大的功能和直观的操作界面,为音乐创作者们提供了一个高效、便捷的创作平台。 一、音乐创作的得力助手 Sibelius Ultimate 2023不仅适用于有抱负的作曲家和词曲作者&a…

# Java 基础面试300题 (51-80)

Java 基础面试300题 (51-80) 051.Java中有那几种循环结构? 循环结构也被称为迭代语句,用于重复执行代码块。Java具有以下几种循环结构: while循环: while语句检查条件,只要条件为真,就会重复…

Python | 武理刷题2

1.文件打开方式 只读模式r 追加写模式a 覆盖写模式w 2. matplotlib绘制 散点图:scatter() 饼图 pie() 直方图:bar() 编程题: 3. 有五个数字:1、2、3、4、5,输出由这五个数字组成的所有互不相同且无重复数字的三位数 #有五个…

计算机网络学习记录 网络层 Day4(上)

计算机网络学习记录 网络层 Day4 (上) 你好,我是Qiuner. 为记录自己编程学习过程和帮助别人少走弯路而写博客 这是我的 github https://github.com/Qiuner gitee https://gitee.com/Qiuner 如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 &#x1f60…

122. 买卖股票的最佳时机 II(中等)

122. 买卖股票的最佳时机 II 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转:122. 买卖股票的最佳时机 II 2.详细题解 实现最大的利润,即只要有盈利就收入囊中,由于交易没有具体限制次数,因此可以依…