算法——链表(1)

在这里插入图片描述

T04BF

👋专栏: 算法|JAVA|MySQL|C语言

🫵 小比特 大梦想

此篇文章与大家分享链表专题的第一部分
如果有不足的或者错误的请您指出!

1.链表常用技巧总结

1.1引入虚拟头结点

在力扣上,基本提供的链表题目都是"无头的",但是针对无头链表,我们最怕的就是参数链表是一个空链表,就容易出现对null的访问.当我们引入虚拟头结点后,我们并不关心这个"头结点"里面放的是什么值,而这个节点只是起到一个哨兵的左右
举一个例子,如果我们要合并两个链表,引入第三链表将两个链表合并
在没有引入虚拟头结点的情况下:
在这里插入图片描述
那么我们的第三个链表就要先判断是否已经有节点了??如果有,直接插在后面即可;如果没有就要将插入的节点作为头结点
但是如果我们引入虚拟头结点
在这里插入图片描述
此时我们就不需要判断了,只需要将两个链表的节点依次插入到newHead后面即可
引入虚拟头结点的优势还有很多,我们在后面的题目中更能感受到

1.2不要吝啬空间

在链表专题,如果我们吝啬空间,有时候会给我们带来很大麻烦
举个例子:
我们通常会做到这样一种题目:在prve和prev.next节点之间插入cur节点
在这里插入图片描述
我们通常会这样做:
①cur.next = prev.next
②prev.next.prev = cur
③prev.next = cur
④cur.prev = prev
这四步操作中,前两步是一定要在后两个之前的
但是如果我们直接将prev.next用用一个临时节点存储起来:
在这里插入图片描述
这是就没必要去担心什么顺序问题了,直接针对三个节点进行操作即可

1.3快慢双指针的利用

快慢双指针在链表操作中经常遇到,而最常用的是我们下面这三种操作,最重要的是这三种操作往往只是作为一道题目里面的一小部分存在

1.3.1判断链表是否有环

题目:判断链表是否有环
在这道题中,我们定义一个fast指针和slow指针,fast指针一次走两步,slow指针一次走两步,那么如果链表没环,那么fast指针一定会走到null,如果链表没环,那么fast指针和slow指针一定会在环的某一点相遇
代码呈现:

public class Solution {public boolean hasCycle(ListNode head) {ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;if(fast == slow){return true;}}return false;}
}

1.3.2找到链表环的入口

题目:找到环的入口
在上一题的基础上,如果链表有环,我们需要找到环的入口
实际上这道题有一个数学推导出来的结论:在fast指针和slow指针相遇点,此时这个相遇点距离环的入口,与起跑点距离环的入口,距离是一样的
在这里插入图片描述
即蓝色路程和红色路程是一样的
那么我们再定义一个节点node在起跑点位置,slow和node同时移动,二者相遇点就是环的入口
代码呈现:

public class Solution {private ListNode isCircle(ListNode head){ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;if(fast == slow){return slow;}}return null;}public ListNode detectCycle(ListNode head) {ListNode node = isCircle(head);if(node == null || node.next == null){return null;}ListNode cur = head;while(cur != node){cur = cur.next;node = node.next;}return cur;}
}

1.3.3删除链表的倒数第k个节点

同样利用双指针,我们让fast指针先走k步,此时fast和slow之间的距离就是k;接着让fast和slow指针同时走,直到fast为null,此时slow和空节点的距离就是k,即为倒数第k个节点
代码呈现:

class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {if(head == null || head.next == null){return null;}ListNode node = new ListNode(-1,head);//解决头结点被删的情况ListNode fast = node;ListNode slow = node;while(n > 0){n--;fast = fast.next;}while(fast.next != null){fast = fast.next;slow = slow.next;}slow.next = slow.next.next;return node.next;}
}

1.3.4寻找中间节点

题目:链表的中间节点
固定套路:定义fast指针和slow指针,fast一次走两步,slow一次走一步,当fast为空或者fast.next 为空时,slow所在位置就是中间节点的位置
代码:

class Solution {public ListNode middleNode(ListNode head) {ListNode fast = head.next;ListNode slow = head;while(fast != null){if(fast.next != null){fast = fast.next.next;}else{fast = fast.next;}slow = slow.next;}return slow;}
}

1.4反转链表

题目:反转链表
这道题如果引入"虚拟头结点",那么在时间复杂度为O(n)的情况下就能完成
即直接往虚拟头结点后面进行头插即可

class Solution {public ListNode reverseList(ListNode head) {ListNode newHead = new ListNode(0);ListNode cur = head;while(cur != null){ListNode tmp = cur.next;cur.next = newHead.next;newHead.next = cur;cur = tmp;}return newHead.next;}
}

2.两数相加

题目:两数相加

2.1解析

思路比较简单,用两个指针遍历两个链表,每次将两个节点里面的值相加,将得到的数的个位数作为新节点的值,把新节点插入到引入的虚拟头结点,同时记录下此时两数相加的进位,在下次计算的时候要加上进位

2.2题解

class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode cur1 = l1;ListNode cur2 = l2;int tmp = 0;ListNode newHead = new ListNode(0);ListNode cur = newHead;//记录新链表的最后一个节点while(cur1 != null || cur2 != null || tmp != 0){//tmp != 0 是为了解决最后计算完还有进位的情况if(cur1 != null){tmp += cur1.val;cur1 = cur1.next;}if(cur2 != null){tmp += cur2.val;cur2 = cur2.next;}ListNode node = new ListNode(tmp % 10);tmp /= 10;cur.next = node;cur = cur.next;}return newHead.next;}
}

3.两两交换链表中的节点

题目:两两交换链表中的节点

3.1解析

这道题就能体现出我们之前说过的"不要吝啬变量"的好处
为了方便,我们还是引入"虚拟头节点"
在这里插入图片描述
对此链表进行两两翻转操作
要翻转两个节点,不仅需要记录这两个节点,还要记录前一个节点和后一个节点
因此我们直接引入这些变量:
在这里插入图片描述
就是对cur和next进行翻转操作,就很简单明了了,直接让prev.next = next; next.next = cur; cur.next = nnext;
在这里插入图片描述
此时前两个就翻转完了
接下来就要让prev指向当前cur的位置,继续进行刚才的操作
在这里插入图片描述
那么循环什么时候结束呢??会有两种情况
(1)就像我们上面这一组一样,当我们再次把prev指向cur的时候
在这里插入图片描述
此时,没翻转的节点就一个,那么就不用翻转了,即当next == null的时候是循环结束
(2)假设我们没有最后一个节点
在这里插入图片描述
那么此时已经没有节点了,自然就不需要翻转.因此cur == null也是循环结束的标志

3.2题解

class Solution {public ListNode swapPairs(ListNode head) {if(head == null || head.next == null){return head;}ListNode newHead = new ListNode(0,head);ListNode prev = newHead;ListNode cur = prev.next;ListNode next = cur.next;ListNode nnext = next.next;while(cur != null &&  next != null){prev.next = next;next.next = cur;cur.next = nnext;prev = cur;cur = prev.next;if(cur != null){next = cur.next;if(next != null){nnext = next.next;}}}return newHead.next;}
}

4.重排链表

题目:重排链表

4.1解析

此题最简单的思路就是将数组划分为两部分,并将右边的部分逆置,随后依次插入新的链表中
在这里插入图片描述
而其中的操作就是寻找中间节点、链表逆置、合并链表,我们在一开始都是讲过的,因此我们直接代码呈现\

4.2

    private ListNode findCenter(ListNode head){ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;}return slow;}private ListNode reverse(ListNode head){ListNode newHead = new ListNode(1);ListNode cur = head;while(cur != null){ListNode tmp = cur.next;cur.next = newHead.next;newHead.next = cur;cur = tmp;}return newHead.next;}public void reorderList(ListNode head) {ListNode center = findCenter(head);ListNode node = reverse(center.next);//让中心节点的后面部分逆置center.next = null;//断开两部分ListNode cur1 = head;//遍历前一部分ListNode newHead = new ListNode(0);ListNode cur = newHead;//遍历新链表//合并while(cur1 != null){//前面的部分一定比后面的部分长cur.next = cur1;cur1 = cur1.next;cur = cur.next;if(node != null){cur.next = node;node = node.next;cur = cur.next;}}head = newHead.next;}

感谢您的访问!!期待您的关注!!!

在这里插入图片描述

T04BF

🫵 小比特 大梦想

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

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

相关文章

【话题】程序员35岁会失业吗?

大家好,我是全栈小5,欢迎阅读小5的系列文章,这是《话题》系列文章 目录 背景招聘分析一、技术更新换代的挑战二、经验与技术的双重优势三、职业发展的多元化选择四、个人成长与职业规划的平衡五、结语文章推荐 背景 35岁被认为是程序员职业生…

数据治理与大数据平台解决方案(免费|可下载)

1、知识星球下载: 如需下载完整PPTX可编辑源文件,请前往星球获取:https://t.zsxq.com/191Y7dD3p 2、免费领取步骤: 【1】关注公众号 方案驿站 【2】私信发送 数据治理与大数据平台 【3】获取本方案PDF下载链接,直接…

007 CSS的继承和层叠 元素特性

文章目录 CSS属性的继承CSS属性的层叠选择器的权重 HTML元素的类型编写HTML注意事项元素隐藏方法CSS属性-overflowCSS样式不生效可能原因 CSS属性的继承 如果一个属性具备继承性,那么在该元素上设置后,它的后代元素都可以继承这个属性 如果后代元素自己…

2023年度总结:允许迷茫,破除迷茫;专注自身,把握当下

0、前言 📜为什么24年已经过了几个月,才提笔写这年度总结呢?毫不羞愧直问我的内心,其实就是懒罢了。直到前几天朋友看到了我去年写的总结,我自己点进那篇总结,完完整整的看了一遍,又翻看我23年…

C语言 | Leetcode C语言题解之第12题整数转罗马数字

题目: 题解: const char* thousands[] {"", "M", "MM", "MMM"}; const char* hundreds[] {"", "C", "CC", "CCC", "CD", "D", "DC"…

Vue2(完结):replace属性、编程式路由导航、缓存路由组件、两个新钩子、路由守卫、history与hash

一、router-link的replace属性 1、作用:控制路由跳转时操作浏览器历史记录的模式 2、浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push 3、如何开启repla…

敏感信息泄露漏洞

法律声明 参与培训需要遵守国家法律法规,相关知识只做技术研究,请勿用于违法用途,造成任何后果自负与本人无关。 中华人民共和国网络安全法(2017年6月1日起施行) 第二十二条 任何个人和组织不得从事入侵他人网络、干扰…

C——找单身狗2

题目内容: 在一个数组中,室友两个数字出现了一次,其他所有数字都出现了两次。找出只出现一次的数字。 如:1,2,3,4,5,1,2,3,4&#xff…

【云计算】云数据中心网络(一):VPC

云数据中心网络(一):VPC 1.什么是 VPC2.VPC 的组成2.1 虚拟交换机2.2 虚拟路由器 3.VPC 网络规划3.1 VPC 数量规划3.2 交换机数量规划3.3 地址空间规划3.4 不同规模企业地址空间规划实践 4.VPC 网络高可靠设计4.1 单地域单可用区部署4.2 单地…

【Vue3】自定义Modal的fixed无效

现有一个模态框&#xff0c;目前一切正常&#xff0c;Modal可以在视口正确位置展示 <template><div class"father"><h3>模态框的父组件</h3><button click"showModal !showModal">显示/隐藏modal</button><div …

NzN的C++之路--this指针

在已经入门了类和对象之后&#xff0c;今天我们来到了类和对象的part2部分--this指针。先三连后看是好习惯&#xff01;&#xff01;&#xff01; 目录 一、this指针的引入 二、this指针的特性 三、this指针必会 四、C语言和C实现Stack的对比 1. C语言实现 2. C实现 一、…

如何确认RID池是否耗尽,以及手动增加RID池大小

确认RID池是否耗尽&#xff1a; 事件查看器&#xff1a; 在RID主控域控制器上打开事件查看器&#xff0c;导航至“Windows日志 > 应用程序和服务日志 > Microsoft > Windows > Directory Service > Operations”。搜索事件ID 16656和16657。事件ID 16656表明RID…

Jupyterlab+内网云穿透傻瓜式教程

文章目录 Jupyterlab内网云穿透傻瓜式教程1、Miniforge安装2、Jupyter Lab安装3、Python语言服务器安装4、PowerShell 7安装5、更改jupyter lab配置6、内网穿透7、高级体验 Jupyterlab内网云穿透傻瓜式教程 1、Miniforge安装 如下图&#xff0c;以Windows安装为例&#xff0c…

DFS:floodfill算法解决矩阵联通块问题

floodfill&#xff0c;翻译为洪水灌溉&#xff0c;而floodfill算法本质上是为了解决在矩阵中性质相同的联通块问题。 一、图像渲染 . - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int dx[4]{0,0,1,-1};int dy[4]{1,-1,0,0};int prev;//记住初始值int m,…

LangChain-10(2) 加餐 编写Agent获取本地Docker运行情况 无技术含量只是思路

可以先查看 上一节内容&#xff0c;会对本节有更好的理解。 安装依赖 pip install langchainhub编写代码 核心代码 tool def get_docker_info(docker_name: str) -> str:"""Get information about a docker pod container info."""result…

色彩在设计中的重要性

title: 色彩在设计中的重要性 date: 2024/4/6 19:08:21 updated: 2024/4/6 19:08:21 tags: 色彩心理品牌识别用户体验文化差异创意设计视觉传达易读性 色彩是设计中不可或缺的元素&#xff0c;它不仅可以影响人的情绪和心理状态&#xff0c;还可以在品牌识别、用户体验、文化差…

【C++练级之路】【Lv.19】【STL】unordered_set类和unordered_map类的模拟实现

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、哈希表&#xff08;改造版&#xff09;1.1 结点1.2 迭代器1.2.1 operator 1.3 本体1.3.1 成员变量和…

掌握 TypeScript 核心:从基本类型到面向对象编程,理论详解与Vue3实践运用

TypeScript 是一种开源的编程语言&#xff0c;由微软公司开发&#xff0c;于2012年10月首次公开发布。 TypeScript 是 JavaScript 的超集&#xff0c;这意味着任何合法的 JavaScript 代码都是有效的 TypeScript 代码。它在 JavaScript 的基础上添加了静态类型系统、类、接口、模…

【Linux】有关时间的命令(date、timedatectl)

专栏文章索引&#xff1a;Linux 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、data命令 1.介绍 2.常用参数 3.常用选项 二、timedatectl命令 1.介绍 2.常用子命令 一、data命令 1.介绍 date命令用于显示或设置系统的时间与日期&#xff0c;语法格式为&a…

Nacos 入门篇---客户端如何发起服务注册?怎么发送服务心跳的(二)

一、引言 上个章节我们简单学习和使用了下Nacos服务自动注册&#xff0c;本文就来分析下Nacos客户端自动注册服务是怎么实现的&#xff5e; 二、目录 目录 一、引言 三、Nacos 源码编译 1.1 拉取代码 1.2 运行起来 四、客户端使用版本选择 五、Nacos客户端项目启动为什么会…