【算法学习】链表篇:链表的常用技巧和操作总结

news2025/4/17 13:19:34

算法学习:

https://blog.csdn.net/2301_80220607/category_12922080.html?spm=1001.2014.3001.5482

前言:

在各种数据结构中,链表是最常用的几个之一,熟练使用链表和链表相关的算法,可以让我们在处理很多问题上都更加容易,下面我们就开始通过一些经典例题学习链表相关的算法

目录

1. 链表的常用技巧和常用操作

1.1 链表的常用技巧

1.2 链表的常用操作

2. 有关链表的经典题型

2.1 两数相加

2.2 两两交换链表中的节点

2.3 重排链表

2.4 K个一组翻转链表

3. 总结


1. 链表的常用技巧和常用操作

1.1 链表的常用技巧

1.画图!!! -> 直观 + 形象 + 便于我们理解

2.引入虚拟“头"结点

  1.   便于处理边界情况
  2.   方便我们对链表操作

3.不要吝啬空间,大胆去定义变量
4.快慢双指针

  1. 判环
  2. 找链表中环的入口
  3. 找链表中倒数第 n个结点

在做链表链表题时,我们尽量把思路画下来,能够更直观的看到问题所在,同时能引入虚拟头节点就引入虚拟头节点,可以帮助我们处理边界情况

链表中最基础的算法之一就是快慢双指针的使用,熟练掌握可以帮助我们解决很多问题

1.2 链表的常用操作

  • 1.创建一个新节点 new
  • 2.尾插
  • 3.头插(逆序链表的题经常会用到)
     

头插法的具体操作:

以上四步要一步一步来,顺序不能有误

2. 有关链表的经典题型

2.1 两数相加

2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

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

提示:

  • 每个链表中的节点数在范围 [1, 100] 内
  • 0 <= Node.val <= 9
  • 题目数据保证列表表示的数字不含前导零

我们先来结合一个例子理解一下这里的逆序是如何操作的:

其实将数字逆序比正序容易,数字逆序后,我们按照链表相加时,先加个位,再加十位,依次往后相加,符合加法逻辑,所以如果是正序的话我们反倒还需要先将链表颠倒,让它变成逆序后再操作

我们可以结合代码来看一下这个原理图,首先我们需要定义一个整数t,它的作用就是计算链表同一位置两数的和,其实对应的就是加法中的相同权值的位置相加(比如个位+个位),然后将t的个位放入求和链表中的相同位置,t如果十位不为0,代表的其实是要进位,比如上面例子中4+6=10,那么个位是0,我们将0放入求和链表的第二个节点处,t的十位跟随cur1、cur2一起来到权值更高的下一个节点进行新的相加运算

代码实现:

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* cur1=l1,*cur2=l2;
        //创建一个虚拟头节点,记录最终返回结果
        ListNode* newhead=new ListNode(0);   
        ListNode* prev=newhead;    //尾指针
        int t=0;
        while(cur1||cur2||t)
        {
            if(cur1)
            {
                t+=cur1->val;
                cur1=cur1->next;
            }
            if(cur2)
            {
                t+=cur2->val;
                cur2=cur2->next;
            }
            prev->next=new ListNode(t%10);
            t/=10;
            prev=prev->next;
        }
        prev=newhead->next;
        delete newhead;
        return prev;
    }
};

2.2 两两交换链表中的节点

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

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

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

这种解法就比较简单粗暴了,就是直接创建一个全新的链表,将原链表中的值按要求交换后输入这个链表中,这样做的好处就是思路简单,容易想到,缺点就是空间开销大

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head==nullptr||head->next==nullptr) return head;

        ListNode* newhead=swapPairs(head->next->next);
        ListNode* tmp=head->next;
        head->next->next=head;
        head->next=newhead;
        //head->next=tmp->next;
        //tmp->next=head;

        return tmp;
    }
};

这种解法就是上面的那种解法,观察上面的图,简单点来说就是还是在原链表上进行操作,记得处理好边界情况,记得创建一个头节点(方便我们找到链表的其实位置,返回值时简单)

2.3 重排链表

143. 重排链表

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

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

示例 2:

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

提示:

  • 链表的长度范围为 [1, 5 * 104]
  • 1 <= node.val <= 1000

算法原理:

主要思路如图所示,这个题目像让我们做的就是链表头取出一个数字,然后再从链表尾取一个数字直到最后取到中间为止,所以我们可以如上图所示,把链表从中间分为两个,然后将后面的逆序然后合并两个链表即可

代码实现:

class Solution {
public:
    void reorderList(ListNode* head) {
        //处理边界情况
        if(head->next==nullptr||head->next->next==nullptr) return;
        
        //1. 找到链表的中间节点
        ListNode* slow=head,*fast=head;
        while(fast&&fast->next)
        {
            slow=slow->next;
            fast=fast->next->next;
        }
        
        //2. 把slow后面的部分给逆序 -- 头插法
        ListNode* head2=new ListNode(0);
        ListNode* cur=slow->next;
        slow->next=nullptr;  //注意把两个链表给断开
        while(cur)
        {
            ListNode* next=cur->next;
            cur->next=head2->next;
            head2->next=cur;
            cur=next;
        }

        //3. 合并两个链表 --双指针
        ListNode* ret=new ListNode(0);
        ListNode* prev=ret;
        ListNode* cur1=head,*cur2=head2->next;
        while(cur1)
        {
            //先放第一个链表
            prev->next=cur1;
            prev=prev->next;
            cur1=cur1->next;
            //再放第二个链表
            if(cur2){
                prev->next=cur2;
                prev=prev->next;
                cur2=cur2->next;
            }
        }
        head=ret->next;
    }
};

2.4 K个一组翻转链表

25. K 个一组翻转链表

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

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

示例 2:

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

提示:

  • 链表中的节点数目为 n
  • 1 <= k <= n <= 5000
  • 0 <= Node.val <= 1000

算法原理:

主要的解题方法就是上面的那两步
   但是这里也有一些细节需要我们注意:

  1. 每一轮逆序结束后,我们在下一轮头插时记得要在返回链表的尾部进行头插
  2. 在逆序结束后,如果还有剩余的节点记得带上

代码实现:

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        //1. 计算链表中节点个数
        int n=0;
        ListNode* cur=head;
        while(cur)
        {
            n++;
            cur=cur->next;
        }
        int count=n/k;
        ListNode* ret=new ListNode(0);
        ListNode* prev=ret;
        cur=head;
        while(count--)
        {
            ListNode* tmp;
            for(int i=0;i<k;i++){           
            ListNode* next=cur->next;
            cur->next=prev->next;
            prev->next=cur;
            if(i==0) tmp=cur;
            cur=next;
            }
            prev=tmp;
        }
        while(cur){
            prev->next=cur;
            prev=prev->next;
            cur=cur->next;
        }
        return ret->next;

    }
};

3. 总结

以上就是几个经典的链表的例题,通过这几道题,其实我们应该明白的是,要想做好链表相关的题,就一定要把有关链表的基础算法给掌握好,比如如何逆序链表,如何实现头插尾插,如何使用快慢双指针等,把这些基础算法掌握好,然后结合题意,大部分链表题还是能够拿下的

本篇笔记:

感谢各位大佬观看,创作不易,还望各位大佬点赞支持!!!

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

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

相关文章

2台8卡L20服务器集群推理方案

1、整体流程梳理 #mermaid-svg-0aNtsWUnOH7ewXpN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-0aNtsWUnOH7ewXpN .error-icon{fill:#552222;}#mermaid-svg-0aNtsWUnOH7ewXpN .error-text{fill:#552222;stroke:#55…

HarmonyOS:使用geoLocationManager (位置服务)获取位置信息

一、简介 位置服务提供GNSS定位、网络定位&#xff08;蜂窝基站、WLAN、蓝牙定位技术&#xff09;、地理编码、逆地理编码、国家码和地理围栏等基本功能。 使用位置服务时请打开设备“位置”开关。如果“位置”开关关闭并且代码未设置捕获异常&#xff0c;可能导致应用异常。 …

系统分析师(二)--操作系统

概述 进程管理 选项A&#xff1a;该进程中打开的文件 进程中打开的文件是由整个进程来管理的&#xff0c;同一进程下的各个线程都可以对这些打开的文件进行访问和操作&#xff0c;所以进程中打开的文件是可以被这些线程共享的。 选项B&#xff1a;该进程的代码段 进程的代码…

安科瑞测频仪表:新能源调频困局的破局者

安科瑞顾强 在“双碳”目标推动下&#xff0c;风电、光伏等新能源正加速成为电力供应的核心力量。然而&#xff0c;新能源发电的间歇性与波动性&#xff0c;如同一把“双刃剑”&#xff0c;在提供清洁电力的同时&#xff0c;也给电网稳定运行带来了前所未有的挑战。国家能源局…

富士相机照片 RAF 格式如何快速批量转为 JPG 格式教程

富士&#xff08;Fujifilm&#xff09;相机拍摄的 RAW 格式文件&#xff08;RAF&#xff09;因其高质量和丰富的图像信息而受到摄影师的喜爱。然而&#xff0c;RAF 文件通常体积较大且不易于分享或直接使用。为了方便处理&#xff0c;许多人选择将其转换为更通用的 JPG 格式。在…

Linux 入门指令(1)

&#xff08;1&#xff09;ls指令 ls -l可以缩写成 ll 同时一个ls可以加多个后缀 比如 ll -at (2)pwd指令 &#xff08;3&#xff09;cd指令 cd .是当前目录 &#xff08;4&#xff09;touch指令 &#xff08;5&#xff09;mkdir指令 &#xff08;6&#xff09;rmdir和rm…

Redis缓存数据库一致性

前言&#xff1a; 在系统开发中经常使用关系型数据库&#xff0c;为了提升关系型数据库的读性能&#xff0c;一般会使用redis加一层缓存&#xff0c;缓存和数据库是分离的两次操作&#xff0c;本文用来分析如何操作能保证缓存和数据库的数据一致性。 一、读场景 二、写场景 …

Android Coil 3 Fetcher大批量Bitmap拼接成1张扁平宽图,Kotlin

Android Coil 3 Fetcher大批量Bitmap拼接成1张扁平宽图&#xff0c;Kotlin <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><u…

文件相关:treecpmv命令扩展详解

拷贝和移动文件 序号命令对应英文作用01tree [目录名]tree以树状图列出文件目录结构02cp 源文件 目标文件copy复制文件或者目录03mv 源文件 目标文件move移动文件或者目录&#xff0f;文件或者目录重命名 一、 tree命令 &#xff08;1&#xff09;定义 tree 命令可以以树状…

S32K144的m_data_2地址不够存,重新在LD文件中配置地址区域

在开发平台软件的时候代码中超出了64K的内存&#xff0c;单纯在ld文件中&#xff0c;增加m_data_2的存储长度&#xff0c;原先是0x00007000,我将长度修改为0x00008000,起始地址还是0x20000000,软件编译没有报错堆栈超出&#xff0c;但是软件下载到单片机中之后&#xff0c;144不…

【STM32】综合练习——智能风扇系统

目录 0 前言 1 硬件准备 2 功能介绍 3 前置配置 3.1 时钟配置 3.2 文件配置 4 功能实现 4.1 按键功能 4.2 屏幕功能 4.3 调速功能 4.4 倒计时功能 4.5 摇头功能 4.6 测距待机功能 0 前言 由于时间关系&#xff0c;暂停详细更新&#xff0c;本文章中&#xff0c;…

【重装系统】大白菜自制U盘装机,备份C盘数据,解决电脑启动黑屏/蓝屏

1. 准备 U 盘 U 盘容量至少 8G&#xff0c;备份 U 盘的数据&#xff08;后期会格式化&#xff09; 2. 从微软官网下载操作系统镜像 https://www.microsoft.com/zh-cn/software-download/windows11 3. 下载安装大白菜 https://www.alipan.com/s/33RVnKayUfY 4. 插入 U 盘&#…

vue实现目录锚点且滚动到指定区域时锚点自动回显——双向锚点

最近在用vue写官网&#xff0c;别问我为什么用vue写官网&#xff0c;问就是不会jq。。。。vue都出现11年了。。。 左侧目录&#xff1a;点击时&#xff0c;右侧区域可以自动滚动到指定的位置。 右侧区域手动滚动时&#xff0c;左侧锚点可以自动切换到对应的目录上 从而实现…

Flutter Invalid constant value.

0x00 问题 参数传入变量&#xff0c;报错&#xff01; 代码 const Padding(padding: EdgeInsets.all(20),child: GradientProgressIndicator(value: _progress), ),_progress 参数报错&#xff1a;Invalid constant value. 0x01 原因 这种情况&#xff0c;多发生于&#xff…

【精品PPT】2025固态电池知识体系及最佳实践PPT合集(36份).zip

精品推荐&#xff0c;2025固态电池知识体系及最佳实践PPT合集&#xff0c;共36份。供大家学习参考。 1、中科院化学所郭玉国研究员&#xff1a;固态金属锂电池及其关键材料.pdf 2、中科院物理所-李泓固态电池.pdf 3、全固态电池技术研究进展.pdf 4、全固态电池生产工艺.pdf 5、…

如何计算设备电池工作时长?

目录 【mAh&#xff08;毫安时&#xff09;计算方法】 【Wh&#xff08;瓦时&#xff09;计算方法】 【为什么仅用电流&#xff08;mA&#xff09;和时间&#xff08;h&#xff09;就能计算电池使用时长&#xff08;mAh&#xff09;&#xff1f;】 1. mAh 的本质是“电荷量…

抽象类及其特性

目录 1、概念2、语法3、特性4、作用 1、概念 在面向对象中&#xff0c;所有对象都是通过类来描述的&#xff0c;但是并不是所有的类都可以用来描述对象。比如下述例子中的 Animal 类&#xff0c;Dog 类和 Cat 类是 Animal 类的子类&#xff0c;可以分别描述小狗和小猫&#xf…

【教程】xrdp修改远程桌面环境为xfce4

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 xfce4 vs GNOME对比 配置教程 1. 安装 xfce4 桌面环境 2. 安装 xrdp 3. 配置 xrdp 使用 xfce4 4. 重启 xrdp 服务 5. 配置防火墙&#xff…

利用python从零实现Byte Pair Encoding(BPE):NLP 中的“变形金刚”

BPE&#xff1a;NLP 界的“变形金刚”&#xff0c;从零开始的奇幻之旅 在自然语言处理&#xff08;NLP&#xff09;的世界里&#xff0c;有一个古老而神秘的传说&#xff0c;讲述着一种强大的魔法——Byte Pair Encoding&#xff08;BPE&#xff09;。它能够将普通的文本“变形…

部署redis cluster

一。在所有的主机里面设置密码和文件地址 vi /etc/redis/6379.conf 注释&#xff1a;登陆则要使用auth 123456才可以进入redis 配置文件地址和超时时间 二。创建集群&#xff1a;上面主机为master&#xff0c;下面为slave&#xff0c;master和slave会随机分配 先写主节点&…