hot100 -- 链表(中)

不要觉得力扣核心代码模式麻烦,它确实比不上ACM模式舒服,可以自己处理输入输出

只是你对 链表 和 return 的理解不到位

👂 ▶ 屿前世 (163.com)

👂 ▶ see you tomorrow (163.com)

目录

🎂两数相加

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

AC  双指针

AC  栈

AC  计算链表长度

🌼两两交换链表中的节点

AC  递归

AC  迭代

🌼K 个一组翻转链表


🎂两数相加

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

1)l1, l2 长度可能不一样,假设短的后面全是 0,通过三目运算符得到 当前节点的值,比如

n1 = l1 ? l1->val : 0

2)sum = n1 + n2 + 进位,%10 当前位,/10 进位

3)注意给节点赋值方式

tail->next = new ListNode(...);

4)可能漏最后一次进位,while() 结束后还要来一次

时间 O(max(m, n)),空间 O(1)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode *head = nullptr, *tail = nullptr;int temp = 0; // 进位while (l1 || l2) {int n1 = l1 ? l1->val : 0; // l1 的值int n2 = l2 ? l2->val : 0;int sum = n1 + n2 + temp;if (!head) // 第1次head = tail = new ListNode(sum % 10); // 注意赋值方式else {// tail 上一步已经初始化, 所以现在是 tail->nexttail->next = new ListNode(sum % 10); // 先给下一赋值tail = tail->next; // 再移动}temp = sum / 10; // 进位// l1, l2 向后移动if (l1) l1 = l1->next;if (l2) l2 = l2->next;}// 最后一次进位if (temp) tail->next = new ListNode(temp);return head; // 不返回 tail, 防止 nullptr}
};

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

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

注意:链表的题,如果出现 Node->next,那么这个 Node 一定不为 nullptr,否则会报错

1,双指针:一前一后,前面的先移动 n 个位置,然后开始同步移动

2,栈:思路类似双指针,最终都是遍历到待删除节点前一个(从栈顶开始出栈)

3,链表长度:思路类似前面,借助哑节点,避免对删除头节点的处理,遍历两次即可

AC  双指针

时间 O(L),空间 O(1),L 链表长度

自己写的

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode *fast = head, *slow = head;// 前后指针 -- 找到倒数第 n 个节点, 即 slowwhile (n--)fast = fast->next;// 删除头节点if (!fast) {ListNode *temp = head;head = temp->next;delete temp;return head;}while (fast->next)slow = slow->next, fast = fast->next;// 删除 slow 下一节点ListNode *bad = slow->next; // 要删除的节点slow->next = slow->next->next;bad->next = nullptr;delete bad;// 上面处理了头节点被删除的情况,所以这里可以 return headreturn head; }
};

官解重写

删除倒数第 n 个节点,通过指针的 next 来操作,最后的 delete 只是为了手动释放堆区数据(自己new的自己delete)

bad 的作用是,防止删的是第一个元素,因为最终会遍历到删除节点的前一个

如果不用 bad,就像前面的代码一样,特殊处理删除节点是头节点的情况

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {// 初始化 head 上一位置,  bad->next = headListNode *bad = new ListNode(0, head); ListNode *fast = head, *slow = bad; // slow 初始化为 badwhile (n--)fast = fast->next;while (fast) {fast = fast->next;slow = slow->next;}// 此时 slow 位于删除节点 上一位置slow->next = slow->next->next; // 更新连接ListNode *ans = bad->next; // 新的头节点delete bad;return ans; // 返回新的头节点}
};

AC  栈

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {stack<ListNode *> s;// temp 的作用是,防止删的是第一个元素,因为最终会遍历到删除节点的前一个ListNode *temp = new ListNode(0, head);ListNode *cur = temp;// 链表节点全部入栈while (cur) {s.push(cur); // push_back 是 vectorcur = cur->next;}// 弹出 n 个元素后,栈顶就是待删除节点前一个while (n--) s.pop();ListNode *prev = s.top(); prev->next = prev->next->next; // 先重新连接ListNode *ans = temp->next; // 再赋值新的头节点delete temp;return ans;}
};

AC  计算链表长度

同样,类似上面两种,通过头节点前的,哑节点,避免对删除头节点这种情况的处理

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode *temp = new ListNode(0, head); // 哑节点,避免对头节点删除的处理ListNode *cur = temp;int len = 0;// 链表长度while (cur->next) { // 长度容易错len++;cur = cur->next;}cur = temp;int count = len - n;// 哑节点移动 len - n + 1,即待删除节点// 所以,移动 len - n,刚好待删除前一个while (count--) cur = cur->next;cur->next = cur->next->next;ListNode *ans = temp->next; // 新的头节点delete temp;return ans;}
};

🌼两两交换链表中的节点

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

AC  递归

head之前的不用处理,举个例子,比如

转换后 head = swapPairs(temp->next),把两两视作一个整体,那么两两中的后一个,指向哪里,取决于后面递归的结果,所以只需考虑当前层

时间 O(n),空间 O(n)(递归栈深度 n)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:// head 表示递归时,当前两两交换节点的前一个ListNode* swapPairs(ListNode* head) {// 递归出口if (head == nullptr || head->next == nullptr)return head; // 只剩0个 或 1个节点// 只看当前层:交换两个节点ListNode *temp = head->next; head->next = swapPairs(temp->next); // 递归交换剩余节点temp->next = head;return temp; // 返回新的头节点}
};

AC  迭代

类似冒泡排序,直接交换,但是需要借助哑节点 temp,比如

temp->Node1->Node2

👇

temp->Node2->Node1

时间 O(n),空间 O(1)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* swapPairs(ListNode* head) {ListNode *temp = new ListNode(0, head); // 初始 temp->next == headListNode *tempHead = temp; // 头节点前一个// 递归中的 head 是当前节点// 迭代中的 head 只表示原链表头节点// 所以 while 中不能用 head, 应该用 tempwhile (temp->next != nullptr && temp->next->next != nullptr) {ListNode *Node1 = temp->next;ListNode *Node2 = temp->next->next;// temp->Node1->Node2 ----> temp->Node2->Node1temp->next = Node2;Node1->next = Node2->next;Node2->next = Node1;// 新的哑节点temp = Node1;}ListNode *ans = tempHead->next; // 新链表头节点// delete tempHead; // 删除哑节点return ans; // 新的头节点}
};

🌼K 个一组翻转链表

25. K 个一组翻转链表 - 力扣(LeetCode)

模拟:迭代反转 + 新建连接

以下是新建连接的 3 个步骤

k = 3 也一样

和上/下一组新建连接时,要从外层开始,就是p0->next->next到p0->next最后才是p0

p0->next->next = cur; // 下一组头
p0->next = nex; // 上一组尾
p0 = p1; // 更新p0

时间 O(n),空间 O(1)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* reverseKGroup(ListNode* head, int k) {// 链表长度 lenint len = 0;for (ListNode *cur = head; cur; cur = cur->next)len++;// temp->next  ==  head(temp/p0 -- 哑节点/哨兵节点)ListNode *temp = new ListNode(0, head);ListNode *p0 = temp; // p0 k个一组第一个节点的前一个ListNode *nex = nullptr, *cur = head;// k 个一组反转for (; len >= k; len -= k) {// 迭代 -- 反转(参考反转链表I)// 因为哨兵节点的存在,所以是 k 次而不是 k-1 次反转for (int i = 0; i < k; ++i) { // k 次反转ListNode *pre = cur->next; // pre 右移cur->next = nex; // 反转nex = cur; // nex 右移cur = pre; // cur 右移}// 当前组 与 上一组尾&&下一组头 连接ListNode *p1 = p0->next; // 新的p0p0->next->next = cur; // 下一组头p0->next = nex; // 上一组尾p0 = p1; // 更新p0}return temp->next; // 返回新链表的头节点}
};

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

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

相关文章

python 绘制六种激活函数(sigmoid、tanh、relu、softmax、relu、elu)

1、效果 2、实现代码&#xff08;带注释&#xff09; import numpy as np # 导入 numpy 库, 用于数学运算 import matplotlib.pyplot as plt # 导入 matplotlib.pyplot, 用于绘图 import matplotlib as mpl # 导入 matplotlib 库, 用于图形配置plt.rcParams[font.sans-se…

mysql奇葩问题union

单独执行第一条&#xff0c;有三条结果&#xff1b; union之后&#xff0c;只有一条结果&#xff1b; union自动的把重复数据合并了&#xff1b;

Arduino通过I2C驱动MT6701磁编码器并读取角度数据

Arduino通过I2C驱动MT6701磁编码器并读取角度数据 &#x1f4cd;相关篇《Arduino通过Wire库读取AS5600编码器数据》 ✨测试了使用STM32硬件I2C扫描其地址失败。使用软件I2C可以。 &#x1f4d1;MT6701&#xff08;基于差分霍尔的磁性角度传感器芯片&#xff09;芯片特性简介 &…

WPF中DataGrid主从数据(父子数据)展示

在wpf中可以使用DataGrid控件,进行主从数据展示,也称父子数据展示。下面展示纯原生控件编码实现功能(样式自己可以根据需求进行修改)。 效果如下: 点击图标,展开和收缩可以自由的切换,也可以自己重新写一个样式,比如+,-或者类似图标的样式,都是可以的。 1.首先创建一…

多线程传参以及线程的优缺点

进程是资源分配的基本单位 线程是调度的基本单位 笼统来说&#xff0c;线程有以下优点&#xff1a; 创建一个新线程的代价要比创建一个新进程小得多 与进程之间的切换相比&#xff0c;线程之间的切换需要操作系统做的工作要少很多 线程占用的资源要比进程少很多 能充分利用多…

leetcode1448.统计二叉树中的好节点数目

1. 题目描述 题目链接 2. 解题思路 首先看一下题目的“核心”&#xff0c;什么是好节点&#xff1a;从根到该节点 X 所经过的节点中&#xff0c;没有任何节点的值大于 X 的值。也就是说&#xff0c;我们只要知道了从根节点到该节点的所有的值&#xff0c;就可以判断该节点是…

Blender3.0 下载地址及安装教程

Blender是一款开源的3D计算机图形软件&#xff0c;广泛应用于动画制作、游戏开发、建模、渲染等领域。它提供了一套强大的工具和功能&#xff0c;让用户能够进行三维建模、动画制作和视觉效果的创作。 Blender支持多种文件格式的导入和导出&#xff0c;使用户能够与其他软件进…

中国建筑模板出口供应商

随着"一带一路"倡议的深入推进,中国基建企业"走出去"的步伐正在加快。与之相应,建筑模板产品作为工程建设的重要材料,其国际化供应也愈发受到重视。在众多建筑模板生产企业中,贵港市能强优品木业有限公司以其卓越的产品质量和丰富的出口经验,成为了国内知名…

MongoDB分片部署(windows)

OS&#xff1a;win10 MongoDB&#xff1a;4.4.24 分片架构 从图中可以看出&#xff0c;分片集群中主要由三个部分组成&#xff0c;即分片服务器&#xff08; Shard &#xff09;、路由服务器 &#xff08; Mongos &#xff09;以及配置服务器&#xff08; Config Server &am…

Vision GNN: An Image is Worth Graph of Nodes

感受野&#xff1a;在卷积神经网络中,感受野(Receptive Field)是指特征图上的某个点能看到的输入图像的区域,即特征图上的点是由输入图像中感受野大小区域的计算得到的。 感受野并非越大越好&#xff0c;反而可能因为过大而过于发散梯度下降&#xff08;Gradient Descent GD&am…

突破编程_前端_SVG(使用 svg-pan-zoom 库进行平移与缩放)

1 svg-pan-zoom 概述 svg-pan-zoom 是一个轻量级、高性能且易于使用的 JavaScript 库&#xff0c;专为增强 SVG 图像的浏览体验而设计。它提供了平移和缩放功能&#xff0c;使用户能够无缝探索大型或复杂的 SVG 图形。这个库允许用户对SVG图像进行交互操作&#xff0c;包括缩放…

企业数据模型应用:数字化转型的关键引擎

一、引言 在数字化浪潮席卷全球的今天&#xff0c;数据已经成为企业运营、决策和创新的核心要素。企业数据模型作为数据管理的核心工具&#xff0c;正逐渐成为企业数字化转型的重要引擎。本文将深入探讨企业数据模型的基本概念、应用场景、挑战与对策&#xff0c;以及其在数字…

NL2SQL基础系列(1):业界顶尖排行榜、权威测评数据集及LLM大模型(Spider vs BIRD)全面对比优劣分析[Text2SQL、Text2DSL]

NL2SQL基础系列(1)&#xff1a;业界顶尖排行榜、权威测评数据集及LLM大模型&#xff08;Spider vs BIRD&#xff09;全面对比优劣分析[Text2SQL、Text2DSL] Text-to-SQL&#xff08;或者Text2SQL&#xff09;&#xff0c;顾名思义就是把文本转化为SQL语言&#xff0c;更学术一…

数据结构——双向循环链表

目录 前言 一、链表的分类 二、双向循环链表 2.1 开辟新的节点 2.2 链表初始化 2.3 打印链表 2.4 链表的尾插 2.5 链表的头插 2.6 链表的尾删 2.7 链表的头删 2.8 查找链表 2.9 在pos位置之后插入数据 2.10 删除pos位置的数据 三、完整代码实现 四、顺序表和双向…

【C/C++笔试练习】read函数、虚拟存储、用户态、线程特点、缺页处理、调度算法、进程优先级、锁的使用、创建进程、不用加减乘除做加法、三角形

文章目录 C/C笔试练习选择部分&#xff08;1&#xff09;read函数&#xff08;2&#xff09;虚拟存储&#xff08;3&#xff09;用户态&#xff08;4&#xff09;线程特点&#xff08;5&#xff09;缺页处理&#xff08;6&#xff09;调度算法&#xff08;7&#xff09;进程优先…

服务器Linux搭建NPM私有仓库

服务器Linux搭建NPM私有仓库 环境搭建 安装 nodejs nodejs官网&#xff1a;https://nodejs.org/en/download/package-manager 可以去官网自行下载nodejs的Linux版本&#xff0c;但是出于别的原因考虑&#xff0c;可以使用nvm去下载nodejs这样会切换nodejs也方便。 nvm 这…

整数运算超越存储单元表示范围:上溢出、下溢出、回绕

示例&#xff1a; /*** brief how about integer-underflow-overflow? show you here.* author wenxuanpei* email 15873152445163.com(query for any question here)*/ #define _CRT_SECURE_NO_WARNINGS//support c-library in Microsoft-Visual-Studio #include <std…

P5730 【深基5.例10】显示屏

思路&#xff1a; 此题只需要两层循环&#xff0c;通过数组映射即可求出答案 AC代码&#xff1a; #include<iostream>using namespace std;typedef long long ll; const int N 10; int a[N];int main() {ll n,m;cin >> n >> m;for(ll in;i<m;i){ll nu…

leetcode:42.接雨水

单调栈解题思路&#xff1a; 需要知道当前遍历到的元素左边和右边第一个比该元素大的元素。 如果当前遍历到的元素大于栈顶元素&#xff0c;则该元素为栈顶元素右边第一个比它大的元素&#xff0c;此时&#xff0c;栈顶元素的栈内相邻元素是该元素左边第一个比它大的元素。【…

如何自己制作一个网址二维码,可追踪扫描数据?

我们最近收到许多这样的咨询&#xff1a;如何生成能够追踪扫描次数的二维码&#xff1f;那么通过今天的文章&#xff0c;您就可以了解到什么样的二维码可以追踪扫描数据&#xff1f;以及如何制作能够追踪扫描数据的二维码&#xff1f; 一、哪种二维码可以追踪扫描数据&#xf…