「链表」链表原地算法合集:原地翻转|原地删除|原地取中|原地查重 / LeetCode 206|237|2095|287(C++)

news2025/2/24 8:24:23

概述

对于一张单向链表,我们总是使用双指针实现一些算法逻辑,这旨在用常量级别空间复杂度和线性时间复杂度来解决一些问题。

所谓原地算法,是指不使用额外空间的算法。

现在,我们利用双指针实现以下四种行为。


 //Definition for singly-linked list.
 struct ListNode {
     int val;
     ListNode *next;
     ListNode(int x = 0) : val(x), next(NULL) {}
     ListNode(int x, ListNode* node) : val(x), next(node) {}
 };

*注意* :以下算法都暂不考虑动态内存释放问题。

1.原地翻转

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表头。

示例:


 想实现原地翻转,那就改变链表的相对位置关系

我们来想想怎么做:

定义双指针pre=head和cur=head->next,pre总是指向cur的前一个节点。

我们要做的其实就只是把cur转接到head之前即可。

这要分为四步:

①断开cur与下一个节点的链接,用pre来保存cur之后的节点:pre->next=cur->next;

②把cur翻到head之前:cur->next=head;

③现在cur指向的才是head:head=cur;

④让cur继续翻转下一个节点:cur=pre->next;

(pre已经在这个过程中隐式地向前移动了)

这个过程一直程序到cur是nullptr为止。

复杂度

时间复杂度:O(n)

空间复杂度:O(1)

Code

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(!head||!head->next)return head;
         ListNode* pre=head;
         ListNode* cur=head->next;
         while(cur){
             pre->next=cur->next;
             cur->next=head;
             head=cur;
             cur=pre->next;
         }
         return head;
    }
};

2.原地删除

有一个单链表的 head,我们想删除它其中的一个节点 node

给你一个需要删除的节点 node 。你将 无法访问 第一个节点  head

链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。

删除给定的节点。


要直接删除给定的节点,就是给你哪个,我就删哪个

但是单向链表没有前一个节点该怎么删? 

很简单:删掉给定节点伪装成给定节点下一个节点,然后把下一个节点直接干掉。

直接看Code。 

复杂度

时间复杂度:O(1)

空间复杂度:O(1)

Code

class Solution {
public:
    void deleteNode(ListNode* node) {
        node->val=node->next->val;
        node->next=node->next->next;
    }
};

3.原地取中

给你一个链表的头节点 head 。删除 链表的 中间节点 ,并返回修改后的链表的头节点 head 。

示例:

 

删除图1的7和图2的3。 


用快慢指针快速找到中间位置

快指针一次两步,慢指针一次一步,快指针走完是慢指针恰好走到要删除的红色节点处。

证明:链表长度为N,快指针走到末尾的时间为T。

Vfast=2VslowT=N/Vfast则Xslow=T*Vslow=N/2

ListNode* slow=head,*fast=head,*pre=nullptr。

维护slow的前一个节点,然后用上一节的原地删除即可。

复杂度

时间复杂度:O(n)

空间复杂度:O(1)

Code

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

4.原地查重

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。


这一节其实并不是链表,但是可由数组映射至链表:

我们将任意索引i抽象为链表的节点数值,nums[i]抽象为链表的next指针。

那么可以认为我们以某种顺序构建了一张环状链表:因为某两个位置的nums[i]指向了相同的节点。

*注意*:链表序并不是原数组序。

这一部分需要讲解:

我们先认为i==0的位置是头节点,也就是1号节点,随后观察:

     i     0 1 2 3 4
nums[i] = [1,3,4,2,2]                       nums[2]=4
                                           ←---------←
                                           ↓         ↑                    
                                           ↓         ↑
ListNode  0--------->3--------->2--------->4--------→2
           nums[0]=1  nums[3]=2  nums[2]=4  nums[4]=2
节点编号   1          2          3         4          5

现在我们抽象出了一张假想链表,剩下的判环与找环操作详见上一篇文章: 「链表」Floyd判环法(弗洛伊德判圈法|龟兔赛跑法)判环并公式推导找环 / LeetCode 142(C++)

Code

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int fast=0,slow=0;
        do{  
             slow=nums[slow];
             fast=nums[nums[fast]];
        }while(slow!=fast);
        fast=0;
        while(slow!=fast){
            slow=nums[slow];
            fast=nums[fast];
        }
        return slow;
    }
};

总结

原地算法对空间只有几乎可以忽略不计的要求,这使得在有空间限制条件时原地算法有着广泛的应用。

我们介绍的这四种链表原地算法兼具了良好的空间复杂度和时间复杂度,希望可以启发大家对链表算法的思考。

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

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

相关文章

Linux驱动.之I2C,iic驱动层(二)

一、 Linux下IIC驱动架构 本篇只分析&#xff0c;一个整体框架。 1、首先说说&#xff0c;单片机&#xff0c;的i2c硬件接口图&#xff0c;一个i2c接口&#xff0c;通过sda和scl总线&#xff0c;外接了多个设备device&#xff0c;通过单片机&#xff0c;来控制i2c的信号发生&…

VUE和Element Plus

1.VUE 1.下载和配置环境 使用vue编程&#xff0c;我们需要使用到的编程软件是vs code&#xff0c;还需要使用node.js&#xff0c;这个的作用就类似于JDK&#xff0c;当我们都下载好之后&#xff0c;winR键打开命令提示符&#xff0c;我们在这里可以查看版本&#xff0c; npm…

《计算机网络 - 自顶向下方法》阅读笔记

《计算机网络 - 自顶向下方法》阅读笔记 应用层、运输层、网络层、数据链路层 计算机网络和因特网&#xff1a; 因特网&#xff1a; ​ 是一个世界范围的计算机网络&#xff0c;互联了全世界的计算机设备 计算机设备&#xff1a;手机&#xff0c;电脑&#xff0c;游戏机&#…

MATLAB数据可视化:在地图上画京沪线的城市连线

matlab自带的geoplot(lat,lon) 可以在地理坐标中绘制线条。使用 lat和lon分别指定以度为单位的经度和纬度坐标。 绘制京沪线所经城市线条&#xff1a; citys [116.350009,39.853928; 116.683546,39.538304; 117.201509,39.085318; 116.838715,38.304676;...116.359244,37.436…

Java网络编程——HTTP协议原理

协议 我们在网上冲浪时&#xff0c;会在浏览器地址栏输入一个网址&#xff0c;然后就能打开网页了。比如&#xff0c;输入 https://www.douban.com/就可以访问到豆瓣的主页&#xff1a; 那么大家是否好奇&#xff1a;https 是什么意思&#xff0c;作用又是什么呢&#xff1f;…

语言模型简介和Ngram模型(1)

语言模型介绍一 语言模型语言模型概念语言模型应用-语音识别声纹特征提取语言模型挑选成句 语言模型应用-手写识别语言模型应用-输入法语言模型分类语言模型评价指标-困惑度PPL N-gram语言模型马尔科夫假设平滑问题平滑问题解决一平滑问题解决二 插值优化语言模型应用-文本纠错…

unity 创建项目报错feature has expired (H0041),sentinel key not found (H0007)

两个报错同一种处理方式。 1、删除以下路径所有文件&#xff1a;C:\ProgramData\SafeNet Sentinel&#xff08;注意&#xff1a;ProgramData为隐藏文件&#xff09; 2、打开Cmd&#xff08;WinR键&#xff0c;输入cmd回车&#xff09;&#xff0c;进入Unity安装所在盘符&#…

SecureCRT记录会话日志

在使用SecureCRT软件的时候&#xff0c;有个非常实用的功能&#xff1a;记录会话日志&#xff0c;就是可以把当前会话的所有记录保存成文本文件。下面简单介绍一下如何使用这个功能。 首先点击SecureCRT软件左上角的文件 然后点击会话日志即可 然后选择一个路径保存日志&#…

物流仓库安全视频智能管理方案:构建全方位、高效能的防护体系

一、背景分析 随着物流行业的快速发展和仓储需求的日益增长&#xff0c;仓库安全成为企业运营中不可忽视的重要环节。传统的人工监控方式不仅效率低下&#xff0c;且难以做到全天候、无死角覆盖&#xff0c;给仓库资产和人员安全带来潜在风险。因此&#xff0c;引入仓库安全视…

Datawhale AI夏令营第四期 魔搭-AIGC方向 task01笔记

目录 赛题内容 可图Kolors-LoRA风格故事挑战赛 baseline要点讲解(请配合Datawhale速通教程食用) Step1 设置算例及比赛账号的报名和授权 Step2 进行赛事报名并创建PAI实例 Step3 执行baseline Step4 进行赛题提交 微调结果上传魔搭 lora 调参参数介绍及 SD 的基础知识点…

ST-LINK烧录MCU

打开ST-LINK软件&#xff1a; 主板断电状态下接入烧录器&#xff0c;烧录器USB连接电脑&#xff1a; 主板上电&#xff0c;点击连接按钮&#xff1a; 点击加载文件&#xff1a; 点击写入按钮&#xff0c;烧录成功后拔掉烧录器&#xff0c;主板重新上电

CPU 流水线技术初识

在当今数字化的时代&#xff0c;计算机已经成为我们生活中不可或缺的一部分。而在计算机的核心部位&#xff0c;中央处理器&#xff08;CPU&#xff09;则是其重要的组成部分。CPU 的性能决定了计算机的运行速度和处理能力&#xff0c;而流水线技术则是 CPU 性能提升的关键所在…

SCAU华南农业大学 高级程序语言设计(C语言)OJ实验题解

有错漏/建议/意见 欢迎在评论区提出&#xff01;&#xff01;&#xff01; 实验1 C语言程序初步 堂前习题 6567 第一个C程序 描述&#xff1a; 将下列程序输入Visual C&#xff0c;编译、连接和运行该程序&#xff0c;运行通过后&#xff0c;提交程序。 输入&#xff1a; …

不同环境下RabbitMQ的安装-3 操作RabbitMQ

前面两篇从不同环境下RabbitMQ的安装-1 为什么要使用消息服务 到同环境下RabbitMQ的安装-2 ARM架构、X86架构、Window系统环境下安装RabbitMQ介绍了关于如何在ARM架构、X86架构和Window系统下如何安装&#xff0c;各位小伙伴可以根据自己的实际开发场景参考安装。 到本篇是一些…

宿主机与容器(docker)之间的数据共享

目录 一台宿主机上的容器和宿主机之间的数据共享 创建卷 进入Docker的卷的存储位置 进入卷ep1的数据存储位置 创建容器并挂载至卷ep1上 测试&#xff1a; 进入容器内部查看 一台宿主机上的多个容器之间的数据共享 挂载新的docker容器在该卷上 查看修改的数据是否一致…

CocosCreator使用 ProtoBuf WebSocket与服务器对接方法

在 Cocos Creator 中使用 .proto 文件和转换成 TypeScript&#xff08;TS&#xff09;两者各有其优缺点&#xff0c;具体选择取决于你的项目需求和团队的开发习惯。以下是两者的一些比较&#xff1a; 1、使用 .proto 文件的优点&#xff1a; 跨语言支持&#xff1a;Protocol B…

对目录的操作

1.fileno&#xff1a;获得文件流指针里的文件描述符 int fd fileno(FILE *fp) 成功返回文件描述符 失败返回-1 2.fdopen:与fileno相反&#xff0c;将文件描述符转换为文件流指针 FILE *fp fdopen(int fd) 成功返回文件流指针 失败返回-1 一、目录&#x…

药物研发企业专属项目管理系统案例(PMS)分享:丽珠医药集团上线瑞杰 SuperProject 系统

丽珠医药集团股份有限公司与北京瑞杰科技达成合作&#xff0c;丽珠医药集团选择瑞杰科技自主研发的 SuperProject 系统来打造一套专业的医药研发项目管理平台&#xff0c;帮助丽珠医药更好地规划、执行和监控药物研发项目&#xff0c;确保项目按时、按质、按量完成&#xff0c;…

数学规划模型|线性规划|整数规划

规划模型的概念 如何来分配有限资源&#xff0c;从而达到人们期望目标的优化分配数学模型&#xff0c;它在数学建模中处于中心地位。 这类问题一般可以归结为数学规划模型&#xff0c;规划模型的应用极为广泛&#xff0c;其作用已为越来越多的人所重视 规划模型是数学建模竞赛…

翰德恩赋能中国邮政信息科技产品创新系列培训

为了增强中邮信科公司需求分析工程师的专业素养&#xff0c;提升其业务需求和业务价值的挖掘能力&#xff0c;进而设计并交付满足用户期望的产品&#xff0c;提升用户体验&#xff0c;运营管理部于2024年4月至6月成功举办了六期需求分析工程师能力提升系列培训。 本次系列培训…