链表专题-03

embedded/2025/2/11 9:20:07/

链表专题(三)

两数相加

问题

[力扣2] 2. 两数相加 - 力扣(LeetCode)

问题描述

给你两个 非空链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

img

java">输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

示例 2:

java">输入:l1 = [0], l2 = [0]
输出:[0]

示例 3:

java">输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

解决方案

定义两个链表的临时索引: curr1,curr2。

定义第三个链表的虚拟头结点: dummy,及其临时索引curr3。

image-20241010165228701

从第一个、二个节点中拆一个节点计算值并存入第三个链表

tips: 需要记录两数相加的进位up(0/1)

image-20241010170130448

java">int t = 0;
if (curr1 == null) { //第一个链表运算结束t = curr2.val + up;curr2 = curr2.next;
} else if (curr2 == null) { //第二个链表运算结束t = curr1.val + up;curr1 = curr1.next;
} else { //两个链表运算都没有结束t = curr1.val + curr2.val + up;curr1 = curr1.next;curr2 = curr2.next;
}
up = t / 10;   //计算进位值(0,1)
curr3.next = new ListNode(t % 10); //计算新节点的值大于10则取余
curr3 = curr3.next;

如果计算完成后超出链表的长度(即计算的结果超出了链表的长度),需要额外的添加节点存储进位up(up=1)

if(up ==1){

curr3.next = new ListNode(up);

}

[参考实现]

java">/*** 遍历两个链表将两个链表相加添加到第三个链表节点上*/
public ListNode addTwoNumbers(ListNode head1, ListNode head2) {int up = 0;ListNode dummy = new ListNode(-1); //虚拟头结点记录第三个链表(head未知)ListNode curr1 = head1;ListNode curr2 = head2;ListNode curr3 = dummy;/***  两个链表有空则计算另一个链表,直到最后一个链表完成计算*/while (curr1 != null || curr2 != null) { int t = 0;if (curr1 == null) { //第一个链表运算结束t = curr2.val + up;curr2 = curr2.next;} else if (curr2 == null) { //第二个链表运算结束t = curr1.val + up;curr1 = curr1.next;} else { //两个链表运算都没有结束t = curr1.val + curr2.val + up;curr1 = curr1.next;curr2 = curr2.next;}up = t / 10;   //计算进位值(0,1)curr3.next = new ListNode(t % 10); //计算新节点的值大于10则取余curr3 = curr3.next;}//如果计算有进位值=1,则需要添加一个节点if (up == 1) {curr3.next = new ListNode(up);}return dummy.next;
}

两两交换链表中的节点

问题

[力扣24] 24. 两两交换链表中的节点 - 力扣(LeetCode)

问题描述

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

img

java">输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

java">输入:head = []
输出:[]

示例 3:

java">输入:head = [1]
输出:[1]

解决方案

定义虚拟头结点dummy: dummy = new ListNode(-1,head);

定义临时节点tmp: tmp = dummy.next;

image-20241011141129405

image-20241011141807856

java">ListNode dummy = new ListNode(-1, head);
ListNode temp = dummy;while (temp.next != null && temp.next.next != null) {ListNode curr = temp.next; //当前节点ListNode next = temp.next.next; //当前节点的下一个节点//节点交换temp.next = next;curr.next = next.next;next.next = curr;temp = curr;
}
return dummy.next;

[参考实现]

java">public ListNode swapPairs(ListNode head) {ListNode dummy = new ListNode(-1, head);ListNode temp = dummy;while (temp.next != null && temp.next.next != null) {ListNode curr = temp.next; //当前节点ListNode next = temp.next.next; //当前节点的下一个节点//节点交换temp.next = next;curr.next = next.next;next.next = curr;temp = curr;}return dummy.next;
}

链表进行插入排序

问题

[力扣147] 147. 对链表进行插入排序 - 力扣(LeetCode)

问题描述

给定单个链表的头 head ,使用 插入排序链表进行排序,并返回 排序后链表的头

插入排序 算法的步骤:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。

链表进行插入排序。

img

示例 1:

img

输入: head = [4,2,1,3]
输出: [1,2,3,4]

示例 2:

img

输入: head = [-1,5,3,4,0]
输出: [-1,0,3,4,5]

解决方案

[初始化]

  1. 虚拟头结点dummy = new ListNode(-1,head);
  2. 记录排序后的后一个节点 sortedLast = dummy.next(先指向head位置): sortedLast记录插入点
  3. 待操作的节点curr = dummy.next.next。

image-20241012125153242

如果sortedLast.val < curr.val, 准备进入循环移动小的节点

image-20241012130233941

如果sortedLast.val > curr

image-20241012130306708

从dummy开始查找比curr小的前一个节点位置

image-20241012131514226

找到比curr小的位置,如图目前pre = dummy, 因为节点4的值大于节点2的值。

image-20241012132519791

java">sortedLast.next = curr.next; // curr小于sortedLast,那么curr即为sortedLast的新记录
curr.next = pre.next;
pre.next = curr;

移动curr索引

image-20241012132837492

java">  curr = sortedLast.next;

[参考代码]

java">public ListNode insertionSortList(ListNode head) {if(head == null) return null;ListNode dummy = new ListNode(-1, head);ListNode sortedLast = dummy.next; // 排好序后的最后一个节点,类似于插入排序已排好序的最后一个位置值ListNode curr = dummy.next.next; // 待插入的节点while (curr != null) {// 当前待插入节点大于于排序序节点的最后一个节点,最后一个节点后移(tip: 已经不是最后一个了)if (sortedLast.val <= curr.val) {sortedLast = sortedLast.next;} else {// curr节点值小于排序好序的最后一个节点,需要向前查找合适位置(curr.val大于的位置)ListNode pre = dummy;while (pre.next.val <= curr.val) { // 移动pre找到比curr.val大的位置前一个位置pre = pre.next;}sortedLast.next = curr.next; // curr小于sortedLast,那么curr即为sortedLast的新记录curr.next = pre.next;pre.next = curr;}curr = sortedLast.next;}return dummy.next;
}

删除链表的倒数第N个节点

问题

[力扣19] 19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

问题描述

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

img

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

解决方案

虚拟头结点及快慢指针法

【初始化】

  • 虚拟头结点 : dummy = new ListNode(-1,head);
  • 快慢索引(指针): ListNode fast = dummy; ListNode slow= dummy;

image-20241012133525414

让快指针(fast)先走n步。

image-20241012133903208

java">for (int i = n; i > 0; i--)
fast = fast.next;

两个指针(fast)和slow同时走到链表结尾。

如图所示,slow的末尾即与末尾的n个位置

image-20241012134816910

java">while (fast!=null &&fast.next != null) {fast = fast.next;slow = slow.next;
}

image-20241012135153109

slow.next = slow.next.next;
return pre.next;

[参考代码]

java">public ListNode removeNthFromEnd(ListNode node, int n) {
ListNode pre = new ListNode(-1, node); // 定义要删除节点的前一个节点
// 定义快慢指针让其距离差n,让fast先走n个节点,fast与slow之间就差n
ListNode fast = pre;
ListNode slow = pre;
// slow ----------n------------- fast
for (int i = n; i > 0; i--)fast = fast.next;// 两个节点同时移动,走到末尾,那么节点slow即为从末尾到n的节点
while (fast!=null &&fast.next != null) {fast = fast.next;slow = slow.next;
}slow.next = slow.next.next;
return pre.next;
}

合并两个有序链表

题目

[力扣21] 21. 合并两个有序链表 - 力扣(LeetCode)

题目描述

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:

img

java">输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

java">输入:l1 = [], l2 = []
输出:[]

示例 3:

java">输入:l1 = [], l2 = [0]
输出:[0]

解决方案

拆除重组法

image-20241012164322144

参考实现

java">public ListNode mergeTwoLists(ListNode head1, ListNode head2) {ListNode dummy = new ListNode(-1);ListNode curr1 = head1;ListNode curr2 = head2;ListNode curr = dummy;while (curr1 != null || curr2 != null) {if (curr1 == null) {curr.next = curr2;curr2 = curr2.next;} else if (curr2 == null) {curr.next = curr1;curr1 = curr1.next;} else if (curr1.val < curr2.val) {curr.next = curr1;curr1 = curr1.next;} else {curr.next = curr2;curr2 = curr2.next;}curr = curr.next;}return dummy.next;}
java">public ListNode mergeTwoLists(ListNode head1, ListNode head2) {if (head1 == null) return head2;if (head2 == null) return head1;ListNode newNode = head1.val < head2.val ? head1 : head2;newNode.next = mergeTwoLists(newNode.next, head1.val >= head2.val ? head1 : head2);return newNode;}

合并K个升序链表

题目

[力扣23] 23. 合并 K 个升序链表 - 力扣(LeetCode)

题目描述

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表

示例 1:

java">输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[1->4->5,1->3->4,2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

java">输入:lists = []
输出:[]

示例 3:

java">输入:lists = [[]]
输出:[]

解决方案

将每个节点的头结点放入优先队列,重新组装链表

[初始化]

  • 优先链表定义
  • 虚拟头结点
image-20241012161144354
java">PriorityQueue<ListNode> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(o -> o.val));ListNode dummy = new ListNode(-1);
ListNode curr = dummy;

链表头节点放入优先队列(优先小队列)

image-20241012161247628
java">for (ListNode head : lists) {if(head !=null) priorityQueue.offer(head);
}

从优先队列中取出最小值,将头结点的下一个节点放入队列。

image-20241012161441656

java">while (!priorityQueue.isEmpty()) {ListNode node = priorityQueue.poll();curr.next = node;if (node.next != null) {priorityQueue.offer(node.next);}curr = curr.next;
}

[参考解答]

java">public ListNode mergeKLists(ListNode[] lists) {if(lists == null) return null;PriorityQueue<ListNode> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(o -> o.val));ListNode dummy = new ListNode(-1);
ListNode curr = dummy;for (ListNode head : lists) {if(head !=null) priorityQueue.offer(head);
}while (!priorityQueue.isEmpty()) {ListNode node = priorityQueue.poll();curr.next = node;if (node.next != null) {priorityQueue.offer(node.next);}curr = curr.next;
}
return dummy.next;
}

分割链表

题目

[力扣86] 86. 分隔链表 - 力扣(LeetCode)

题目描述

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。你应当 保留 两个分区中每个节点的初始相对位置。

示例 1:

image-20241012172418081

java">输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]

示例 2:

java">输入:head = [2,1], x = 2
输出:[1,2]

解决方案

image-20241012174129136

image-20241012174336348

java">ListNode<Integer> dummyLess = new ListNode<>(-1);
ListNode<Integer> dummyLarge = new ListNode<>(-2);ListNode<Integer> curr = head;
ListNode<Integer> currLess = dummyLess;
ListNode<Integer> currLarge = dummyLarge;while (curr != null) {if (curr.val < x) {currLess.next = curr;currLess = currLess.next;} else {currLarge.next = curr;currLarge = currLarge.next;}curr = curr.next;
}currLess.next = dummyLarge.next;
currLarge.next =null;
return dummyLess.next;

http://www.ppmy.cn/embedded/161290.html

相关文章

Node.js 完全教程:从入门到精通

Node.js 完全教程&#xff1a;从入门到精通 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;允许开发者在服务器端使用 JavaScript。它的非阻塞 I/O 和事件驱动架构使得 Node.js 非常适合于构建高性能的网络应用。本文将详细介绍 Node.js 的安装、基本语…

重生之我要当云原生大师(十四)分析和存储日志

目录 一、简述常用的日志文件所存储的消息类型。 二、syslog的优先级&#xff1f; 三、维护准确时间的意义&#xff1f; 一、简述常用的日志文件所存储的消息类型。 1. 系统日志文件 /var/log/messages 消息类型&#xff1a;通用的系统日志文件&#xff0c;记录系统启动、…

502 Bad Gateway 错误详解:从表现推测原因,逐步排查直至解决

502 Bad Gateway 错误通常意味着服务器之间的通信失败&#xff0c;但导致的具体原因往往因场景而异。 场景一&#xff1a;高峰期频繁出现 502 错误 1.1 现象 在流量高峰期间&#xff08;如促销活动、直播发布等&#xff09;&#xff0c;页面访问变慢甚至出现 502 错误&#…

JVM栈帧中|局部变量表、操作数栈、动态链接各自的任务是什么?

局部变量表和动态链接确实在栈帧中存在&#xff0c;用于存储方法的参数、局部变量和方法的动态链接信息&#xff08;如常量池索引等&#xff09;&#xff0c;但这些并不等同于操作数栈。 让我们理清楚两者之间的区别和它们各自的作用。 &#x1f680; 栈帧和操作数栈的关系 1…

vue安装过程中遇到错误提示“npm ERR!”该如何解决?

在安装过程中遇到 npm ERR! 错误是比较常见的,通常可能由多种原因引起。以下是一些常见的错误及其解决方法: 一、常见错误及解决方案 1. 检查 Node.js 和 npm 版本 确保你的 Node.js 和 npm 版本是最新的。你可以通过以下命令检查版本: node -v npm -v如果版本较旧,请更…

中间软设笔记

第1章 计算机系统知识 1.1 计算机系统基础知识 一、中央处理单元 1、CPU 的功能&#xff1a; 程序控制、操作控制、时间控制、数据处理。 2、CPU的组成&#xff1a;CPU主要由运算器、控制器、寄存器组和内部总线等部件组成。 &#xff08;1&#xff09;运算器&#xff1a;…

python基础入门:5.4实战:电商商品管理系统

""" 电商商品管理系统核心模块 包含商品管理、购物车操作、折扣策略和库存控制功能 """class Product:"""商品实体类&#xff0c;负责库存管理"""def __init__(self, sku: str, name: str, price: float, stock: …

【metersphere】创建的变量,在json携带数据的时候,不生效

在前置脚本中&#xff0c;定义变量 在请求体数据中&#xff0c;进行使用&#xff0c;json形式的数据&#xff0c; 在请求体中&#xff0c;进行使用 切换到json_schema 直接使用变量&#xff0c;传输成功