算法巡练day04Leetcode24交换节点19删除倒数节点142环形链表

今天学习的文章和视频链接

https://www.bilibili.com/video/BV1YT411g7br/?vd_source=8272bd48fee17396a4a1746c256ab0ae

https://www.bilibili.com/video/BV1if4y1d7ob/?vd_source=8272bd48fee17396a4a1746c256ab0ae

24两两交换链表中的节点

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

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

输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]
示例 3:

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

提示:

链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100

题目分析

交换相邻两个元素了,此时一定要画图,不画图,操作多个指针很容易乱,而且要操作的先后顺序,画图步骤建议看文章开头的视频链接

我遇到的问题

少写了一句dummyHead->next = head,导致完全没有传参。

我的acm模式代码

#include
#include

struct ListNode {
int val;
ListNode* 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* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead;
while (cur->next != nullptr && cur->next->next != nullptr) {
ListNode* tmp = cur->next;
ListNode* tmp1 = cur->next->next->next;

        cur->next = cur->next->next;cur->next->next = tmp;tmp->next = tmp1;//更新curcur = cur->next->next;}return dummyHead->next;
}// 辅助函数,用于创建一个链表
ListNode* createList(const std::vector<int>& values) {ListNode* dummyHead = new ListNode(0);ListNode* cur = dummyHead;for (int value : values) {cur->next = new ListNode(value);cur = cur->next;}ListNode* head = dummyHead->next;delete dummyHead;return head;
}// 辅助函数,用于打印链表
void printList(ListNode* head) {ListNode* cur = head;while (cur != nullptr) {std::cout << cur->val << " ";cur = cur->next;}std::cout << std::endl;
}

};

int main() {
Solution sol;
// 创建链表
std::vector values = {1, 2, 3, 4, 5};
ListNode* head = sol.createList(values);

// 打印原始链表
std::cout << "Original List: ";
sol.printList(head);// 反转链表ListNode* swapNode = sol.swapPairs(head);// 打印反转后的链表
std::cout << "swap List: ";
sol.printList(swapNode);return 0;

}

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

题目描述

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

输出:[1,2,3,5]

示例 2:

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

示例 3:

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

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

进阶:你能尝试使用一趟扫描实现吗?

我的想法

首先反转链表,在通过n来遍历找到要删除节点的前一个节点进行删除

整体思路

利用快慢指针(妙),快指针比慢指针多走n+1步,让cur指针停在要删除节点的前一个节点

如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。

题目分析

定义fast指针和slow指针,初始值为虚拟头结点

ast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)

fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:

fast和slow同时移动,直到fast指向末尾

删除slow指向的下一个节点

acm模式完整代码

#include <iostream>
#include <vector>struct ListNode {int val;ListNode* next;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* dummyHead = new ListNode(0);dummyHead->next = head;ListNode* fast = dummyHead;ListNode* slow = dummyHead;// n++;while (n-- && fast != nullptr) {fast = fast->next;}fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点while (fast != nullptr) {fast = fast->next;slow = slow->next;}//删除节点ListNode* tmp = slow->next;slow->next = slow->next->next;delete tmp;return dummyHead->next;}// 辅助函数,用于创建一个链表ListNode* createList(const std::vector<int>& values) {ListNode* dummyHead = new ListNode(0);ListNode* cur = dummyHead;for (int value : values) {cur->next = new ListNode(value);cur = cur->next;}ListNode* head = dummyHead->next;delete dummyHead;return head;}// 辅助函数,用于打印链表void printList(ListNode* head) {ListNode* cur = head;while (cur != nullptr) {std::cout << cur->val << " ";cur = cur->next;}std::cout << std::endl;}
};int main() {Solution sol;// 创建链表std::vector<int> values = {1, 2, 3, 4, 5};ListNode* head = sol.createList(values);// 打印原始链表std::cout << "Original List: ";sol.printList(head);// 反转链表ListNode* swapNode = sol.removeNthFromEnd(head, 3);// 打印反转后的链表std::cout << "swap List: ";sol.printList(swapNode);return 0;
}

面试题 02.07. 链表相交

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

在这里插入图片描述

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

示例 1:
在这里插入图片描述

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3

输出:Intersected at ‘8’

解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。

从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。

在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

提示:

listA 中节点数目为 m
listB 中节点数目为 n
0 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
如果 listA 和 listB 没有交点,intersectVal 为 0
如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]

进阶:你能否设计一个时间复杂度 O(n) 、仅用 O(1) 内存的解决方案?

题目分析

简单来说,就是求两个链表交点节点的指针。 这里同学们要注意,交点不是数值相等,而是指针相等。

为了方便举例,假设节点元素数值相等,则节点指针相等。

看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:

(我不理解),今天跳过这道题

142 环形链表

题目分析

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

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

不允许修改 链表。

在这里插入图片描述

提示:

链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引

进阶:你是否可以使用 O(1) 空间解决此题?

整体思路

用快慢指针判断是否有环,快指针每次走两个节点,慢指针每次走一个节点,快指针是一个一个节点靠近慢指针,一定会在环里面相遇

判断链表是否有环

可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

为什么fast 走两个节点,slow走一个节点,有环的话,一定会在环内相遇呢,而不是永远的错开呢

首先第一点:fast指针一定先进入环中,如果fast指针和slow指针相遇的话,一定是在环中相遇,这是毋庸置疑的。

那么来看一下,为什么fast指针和slow指针一定会相遇呢?

可以画一个环,然后让 fast指针在任意一个节点开始追赶slow指针。

会发现最终都是这种情况, 如下图:

在这里插入图片描述

fast和slow各自再走一步, fast和slow就相遇了

这是因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。

如果有环,如何找到这个环的入口

此时已经可以判断链表是否有环了,那么接下来要找这个环的入口了。

假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。

那么相遇时: slow指针走过的节点数为: x + y, fast指针走过的节点数:x + y + n (y + z),n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。

因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:

(x + y) * 2 = x + y + n (y + z)

两边消掉一个(x+y): x + y = n (y + z)

因为要找环形的入口,那么要求的是x,因为x表示 头结点到 环形入口节点的的距离。

所以要求x ,将x单独放在左面:x = n (y + z) - y ,

再从n(y+z)中提出一个 (y+z)来,整理公式之后为如下公式:x = (n - 1) (y + z) + z 注意这里n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针。

这个公式说明什么呢?

先拿n为1的情况来举例,意味着fast指针在环形里转了一圈之后,就遇到了 slow指针了。

当 n为1的时候,公式就化解为 x = z,

这就意味着,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。

那么 n如果大于1是什么情况呢,就是fast指针在环形转n圈之后才遇到 slow指针。

其实这种情况和n为1的时候 效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。

代码如下:

class Solution {
public:ListNode* detectCycle(ListNode* head) {ListNode* fast = head;ListNode* slow = head;while (fast != nullptr && fast->next != nullptr) {slow = slow->next;fast = fast->next->next;if (slow == fast) {ListNode* index1 = fast;ListNode* index2 = slow;while (index1 != index2) {index1 = index1->next;index2 = index2->next;}return index2;}}return nullptr;}};

谁能帮我看看这段代码为什么不能运行通过呢。

为了确定这段代码的时间复杂度,我们需要分析两个主要部分:寻找循环(如果存在)和确定循环的起始点。

寻找循环:这部分使用了快慢指针的方法。慢指针每次移动一步,快指针每次移动两步。如果链表中没有循环,快指针将到达链表的末尾,操作将在O(n)时间内完成,其中n是链表中的节点数。如果链表中有循环,快慢指针最终会在循环中的某个点相遇。这个相遇点最坏情况下会在O(n)时间内发生。确定循环的起始点:一旦快慢指针在循环中相遇,代码中的第二个循环会开始寻找循环的起始点。在最坏的情况下,这个循环会遍历整个链表一次,再次带来O(n)的时间复杂度。

综合以上两部分,整个函数的时间复杂度是O(n)。

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

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

相关文章

ASP.NET Core基础之图片文件(一)-WebApi图片文件上传到文件夹

阅读本文你的收获&#xff1a; 了解WebApi项目保存上传图片的三种方式学习在WebApi项目中如何上传图片到指定文件夹中 在ASP.NET Core基础之图片文件(一)-WebApi访问静态图片文章中&#xff0c;学习了如何获取WebApi中的静态图片&#xff0c;本文继续分享如何上传图片。 那么…

八皇后问题(C语言/C++)超详细讲解/由浅入深---深入八皇后问题

介绍引入 在计算机科学中&#xff0c;八皇后问题是一个经典的回溯算法问题。这个问题的目标是找出一种在8x8国际象棋棋盘上放置八个皇后的方法&#xff0c;使得没有任何两个皇后能够互相攻击。换句话说&#xff0c;每一行、每一列以及对角线上只能有一个皇后。 想象一下&…

为什么大学c语言课不顺便教一下Linux,Makefile

为什么大学c语言课不顺便教一下Linux&#xff0c;Makefile&#xff0c;git&#xff0c;gdb等配套工具链呢? 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「Linux的资料从专业入门到高级教程工具包」&…

Docker 网络管理

一、Docker网络简介 Docker网络是容器化应用程序的重要组成部分&#xff0c;它使得容器之间可以互相通信和连接&#xff0c;同时也提供了容器与外部环境之间的隔离和连接。 二、Docker网络网络模式 Docker 提供了多种网络模式&#xff0c;可以通过docker network ls 命令查看…

MySQL——事物

目录 一.发现问题 二.什么时事物 三.事务提交方式 四.事物的常规操作方式 五. 事务隔离级别 1.如何理解隔离性 2.隔离级别 3.查看与设置隔离性 4.读未提交【Read Uncommitted】 5.读提交【Read Committed】 6.可重复读【Repeatable Read】 7.串行化【serializabl…

Unity游戏资源更新(AB包)

目录 前言&#xff1a; 一、什么是AssetBundle 二、AssetBudle的基本使用 1.AssetBundle打包 2.BuildAssetBundle BuildAssetBundleOptions BuildTarget 示例 3.AssetBundle的加载 LoadFromFile LoadFromMemory LoadFromMemoryAsync UnityWebRequestAsssetBundle 前…

QProgressDialog用法及结合QThread用法,四种线程使用

1 QProgressDialog概述 QProgressDialog类提供耗时操作的进度条。 进度对话框用于向用户指示操作将花费多长时间&#xff0c;并演示应用程序没有冻结。此外&#xff0c;QPorgressDialog还可以给用户一个中止操作的机会。 进度对话框的一个常见问题是很难知道何时使用它们;操作…

Linux shell编程学习笔记38:history命令

目录 0 前言 1 history命令的功能、格式和退出状态1.1 history命令的功能1.2 history命令的格式1.3退出状态2 命令应用实例2.1 history&#xff1a;显示命令历史列表2.2 history -a&#xff1a;将当前会话的命令行历史追加到历史文件~/.bash_history中2.3 history -c&#xf…

如何做好档案数字化前的鉴定工作

要做好档案数字化前的鉴定工作&#xff0c;可以按照以下步骤进行&#xff1a; 1. 确定鉴定目标&#xff1a;明确要鉴定的档案的内容、数量和性质&#xff0c;确定鉴定的范围和目标。 2. 进行档案清点&#xff1a;对档案进行全面清点和登记&#xff0c;包括数量、种类、状况等信…

【Linux】基本指令了解(一)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a;1. 认识Linux1.1 什么是Linux1.2 Linux特点 2. ls指令3. pwd命令4. cd 指令5. touch命令6. mkdir指令7. …

<JavaEE> TCP 的通信机制(二) -- 连接管理(三次握手和四次挥手)

目录 TCP的通信机制的核心特性 三、连接管理 1&#xff09;什么是连接管理&#xff1f; 2&#xff09;“三次握手”建立连接 1> 什么是“三次握手”&#xff1f; 2> “三次握手”的核心作用是什么&#xff1f; 3&#xff09;“四次挥手”断开连接 1> 什么是“…

听GPT 讲Rust源代码--library/panic_unwind

File: rust/library/panic_unwind/src/seh.rs 在Rust源代码中&#xff0c;rust/library/panic_unwind/src/seh.rs这个文件的作用是实现Windows操作系统上的SEH&#xff08;Structured Exception Handling&#xff09;异常处理机制。 SEH是Windows上的一种异常处理机制&#xff…

Mysql 动态链接库配置步骤+ 完成封装init和close接口

1、创建新项目 动态链接库dll 2、将附带的文件都删除&#xff0c;创建LXMysql.cpp 3、项目设置 3.1、预编译头&#xff0c;不使用预编译头 3.2、添加头文件 3.3、添加类 3.4、写初始化函数 4、项目配置 4.1、右键解决方案-属性-常规-输出目录 ..\..\bin 4.2、生成lib文件 右…

3D视觉-相机选用的原则

鉴于不同技术方案都有其适用的场景&#xff0c;立体相机的选型讲究的原则为“先看用途&#xff0c;再看场景&#xff0c;终评精度”&#xff0c;合适的立体相机在方案中可以起到事半功倍的效果。从用途上来进行划分&#xff0c;三维视觉方案主要应用在两个方向&#xff1a;测量…

Linux 进程(六) 环境变量

main函数参数&#xff1a; 这是一个常见的main函数&#xff0c;那么main函数可以带参吗&#xff1f; int main() {return 0; } 答案是可以的&#xff01; 我们先看这样一段代码&#xff0c;首先给main函数带上两个参数。 然后我们来看输出的结果。 这样一组字符串是命令行解释…

【AI】一文读懂大模型套壳——神仙打架?软饭硬吃?

目录 一、套壳的风波此起彼伏 二、到底什么是大模型的壳 2.1 大模型的3部分&#xff0c;壳指的是哪里 大模型的内核 预训练&#xff08;Pre-training&#xff09; 调优&#xff08;Fine-tuning&#xff09; 2.2 内核的发展历程和万流归宗 2.3 套壳不是借壳 三、软饭硬…

Ubuntu 常用命令之 locate 命令用法介绍

&#x1f525;Linux/Ubuntu 常用命令归类整理 locate命令是在Ubuntu系统下用于查找文件或目录的命令。它使用一个预先构建的数据库&#xff08;通常由updatedb命令创建&#xff09;来查找文件或目录&#xff0c;因此它的查找速度非常快。 plocate 安装 locate 不是 Ubuntu 系…

语音AI小夜灯项目

一、项目简介 使用ESP32-S3N8R8模块作为主控芯片&#xff0c;S3内核增加了用于加速神经网络计算和信号处理等的指令&#xff0c;这使得我们可以使用它来快速解析训练好的语音模型进行语音识别的功能。 二、原理解析 本项目由四个部分组成&#xff0c;电源部分、LED照明部分、…

Spring Cloud Gateway 常见过滤器的基本使用

目录 1. 过滤器的作用 2. Spring Cloud Gateway 过滤器的类型 2.1 内置过滤器 2.1.1 AddResponseHeader 2.1.2 AddRequestHeader 2.1.3 PrefixPath 2.1.4 RequestRateLimiter 2.1.5 Retry 2.2 自定义过滤器 1. 过滤器的作用 过滤器通常用于拦截、处理或修改数据流和事…

【Matlab】基于遗传算法优化BP神经网络 (GA-BP)的数据时序预测(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88682033 目录 【Matlab】BP 神经网络时序预测算法 【Matlab】CNN卷积神经网络时序预测算法 【Matlab】ELM极限学习机时序预测算法 【Matlab】基于遗传算法优化BP神经网络 (GA-BP)的数据时序预测 【Mat…