链表OJ题讲解1

news2024/11/25 20:39:49

💓博主个人主页:不是笨小孩👀
⏩专栏分类:数据结构与算法👀
🚚代码仓库:笨小孩的代码库👀
⏩社区:不是笨小孩👀
🌹欢迎大家三连关注,一起学习,一起进步!!💓

链表OJ

  • 删除链表元素
    • 方法一
    • 方法二
  • 反向链表
    • 方法一
    • 方法二
  • 链表的中间结点
  • 链表中倒数第k个结点
  • 合并两个排序列表

在这里插入图片描述

删除链表元素

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法一

我们可以遍历一遍链表,然后将等于val的值的节点删除了,然后在将剩余的链接起来即可。我们就需要两个指针,一个遍历链表另一个记录上一个节点的位置,如果相等就删除链接,等到链表遍历结束,就可以得到新的链表,但是这种放大有一个弊端,就是如果头结点就是val我们无法处理,所以我们需要现将头结点是val的情况处理了,头结点是val,我们只需要头删即可。

代码如下:

struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode* prev = NULL,*cur = head;
    while(cur)
    {
        if(cur->val==val)
        {
            //相等就要删除
            if(cur==head)
            {
                //如果头结点是就相等,就要头删
                head = cur->next;
                free(cur);
                cur = head;
            }
            else
            {
                //正常删除
                prev->next = cur->next;
                free(cur);
                cur = prev->next;
            }
        }
        else
        {
            // 不相等prev记录上一个节点,cur往下走
            prev = cur;
            cur = cur->next;
        }
    }
    return head;
}

方法二

我们可以依旧是遍历原链表,但是我们这一次需要一个新的头,然后与val不相等的我们尾插到新的头中就可以了,这个方法比较省事,直接尾插就可以,但是需要注意新的头为空的情况,为了方便尾插,我们需要一个尾指针来记录尾节点的位置。

代码如下:

struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode* cur = head,*tail=NULL,*newhead=NULL;
    while(cur)
    {
        if(cur->val==val)
        {
            //相等就删除
            struct ListNode* next = cur->next;
            free(cur);
            cur = next;
        }
        else
        {
            //不相等就尾插
            if(newhead==NULL)
            {
                //第一次尾插
                newhead = tail = cur;
                cur= cur->next;
            }
            else
            {
                //正常尾插
                tail->next= cur;
                cur = cur->next;
                tail = tail->next;
            }
        }
    }
    //尾差的最有后一个节点的next要置NULL,不然可能会非法访问
    if(tail!=NULL)
    //tail等于空说明链表为空,或者链表中的元素都val
        tail->next = NULL;
    return newhead;
}

反向链表

在这里插入图片描述
在这里插入图片描述

方法一

我们定义一个空指针,然后翻转链表的指向,但是直接翻转的话我们会丢失下一个节点,所以我们还需要一个指针来记录下一个节点的位置。

代码如下:

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* newhead = NULL,*cur = head,*next = NULL;
    while(cur)
    {
        //next指向下一个节点
        next = cur->next;
        //翻转指向
        cur->next = newhead;
        //更新新的头结点
        newhead = cur;
        //更新cur
        cur = next;        
    }
    return newhead;
}

方法二

头插法,我们遍历原链表,然后把节点都头插到新的头处,即可翻转链表。

代码如下:

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* newhead = NULL,*cur = head;
    while(cur)
    {
        //保存下一个节点
        struct ListNode* next = cur->next;
        //头插
        cur->next = newhead;
        newhead = cur;
        cur = next;
    }
    return newhead;
}

链表的中间结点

在这里插入图片描述
在这里插入图片描述

这个题使用快慢指针就可以解决。我们让慢指针一次走一步,快指针一次走两步,我们就可以知道当快指针为空时,或者当快指针的next为空时此时的慢指针就是中间节点。

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* slow = head,*fast = head;
    while(fast&&fast->next)
    {
    	//慢指针走一步
        slow=slow->next;
        //快指针走两步
        fast = fast->next->next;
    }
    return slow;
}

链表中倒数第k个结点

在这里插入图片描述

这个题同样使用快慢指针,我们可以让快指针先走k步,然后两个指针一起走,当快指针为空时,慢指针就是倒数第k个节点,如果先让快指针走k-1步的话,当快指针的next为空时,慢指针就是倒数第k个节点。这两种方法都可以。我们实现走k步的

代码如下:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode* fast = pListHead,*slow = pListHead;
    while(k--)
    {
        // fast=NULL前K个就为空了(判断k是不是过大,以及链表是不是空链表)
        if(fast==NULL) return NULL;
        fast = fast->next;
    }

    while(fast)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

合并两个排序列表

在这里插入图片描述

这个题我们可以同时遍历两个链表,然后拿小的下来尾插,思想差不多就是这样,我们需要一个头,但是这个头可以是哨兵位,也可以是空,我们这里写两个版本的。

带哨兵位的
代码如下:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
	//如果一个链表为空直接返回另一个链表
    if(list1==NULL) return list2;
    if(list2==NULL) return list1;
    //创建哨兵位
    struct ListNode* newhead = NULL,*tail = NULL;
    newhead = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
    while(list1&&list2)
    {
        if(list1->val<list2->val)
        {
        //不用考虑头结点为空的情况直接尾插就可以
            tail->next = list1;
            tail = tail->next;
            list1= list1->next;
        }
        else
        {
        //不用考虑头结点为空的情况直接尾插就可以
            tail->next = list2;
            tail = tail->next;
            list2= list2->next;
        }
    }
    //如果一个链表为空,直接将另一个链表链接过来
    if(list1==NULL) tail->next = list2;
    if(list2==NULL) tail->next = list1;
    //保返回的头
    struct ListNode* next = newhead->next;
    //释放哨兵位
    free(newhead);
    return next;
}

不带哨兵位
代码如下:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    //如果一个链表为空直接返回另一个链表
    if(list1==NULL) return list2;
    if(list2==NULL) return list1;
    struct ListNode* newhead = NULL,*tail = NULL;
    while(list1&&list2)
    {
        if(list1->val<list2->val)
        {
            //判断头结点是否为空
            if(newhead==NULL)
            {
                newhead = tail = list1;
                list1 = list1->next;
            }
            else
            {
                tail->next = list1;
                tail = tail->next;
                list1= list1->next;
            }
        }
        else
        {
            //判断头结点是否为空
            if(newhead==NULL)
            {
                newhead = tail = list2;
                list2 = list2->next;
            }
            else
            {
                tail->next = list2;
                tail = tail->next;
                list2= list2->next;
            }
            
        }
    }
    //如果一个链表为空,直接将另一个链表链接过来
    if(list1==NULL) tail->next = list2;
    if(list2==NULL) tail->next = list1;
    return newhead;
}

今天的分享就到这里了,感谢大家的支持和关注。

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

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

相关文章

MySQL高级篇第6章(索引的数据结构)

文章目录 1、为什么使用索引2、索引及其优缺点3、InnoDB中索引的推演4、MyISAM中的索引方案5、索引的代价6、MySQL数据结构选择的合理性 1、为什么使用索引 假如给数据使用 二叉树 这样的数据结构进行存储&#xff0c;如下图所示 2、索引及其优缺点 3、InnoDB中索引的推演 4、M…

Spring中声明式事务

声明式事务&#xff1a;基于Spring AOP&#xff0c;通过注解或XML配置实现&#xff0c;有助于用户将操作与事务规则进行解耦。其本质是对方法前后进行拦截&#xff0c;然后在目标方法开始之前创建或者加入一个事务&#xff0c;在执行完目标方法之后根据执行情况提交或者回滚事务…

前端小练-产品宣传页面

文章目录 前言页面结构固定钉头部轮播JS特效 完整代码总结 前言 经过一个月的爆肝&#xff0c;花费了一个月&#xff08;期间还花费了将近半个月的时间打比赛&#xff0c;还要备研&#xff09;算是把数二高数的内容强化了一遍&#xff0c;接下来刷熟练度即可&#xff0c;可惜的…

VirtualBox Ubuntu无法安装增强功能以及无法复制粘贴踩坑记录

在VirtualBox安装增强功能想要和主机双向复制粘贴&#xff0c;中间查了很多资料&#xff0c;终于是弄好了。记录一下过程&#xff0c;可能对后来人也有帮助&#xff0c;我把我参考的几篇主要的博客都贴上来了&#xff0c;如果觉得我哪里讲得不清楚的&#xff0c;可以去对应的博…

前端生成图片验证码怎么做?

##题记&#xff1a;我们实现一个功能首先想一下我们需要做哪些工作&#xff0c;比如我们需要生成一个随机的图片验证码&#xff0c;我们需要一个就是点击事件获取验证码&#xff0c;通过接口我们去获取图片路径进行渲染就行&#xff0c;这里边还要牵扯一件事情就是获取一个随机…

uniapp开发小程序-实现中间凸起的 tabbar

一、效果展示&#xff1a; 二、代码实现&#xff1a; 1.首先在pages.json文件中进行tabbar的样式和列表配置&#xff0c;代码如下&#xff1a; {"pages": [ //pages数组中第一项表示应用启动页&#xff0c;参考&#xff1a;https://uniapp.dcloud.io/collocation/p…

Stable Diffusion AI绘画学习指南【本地环境搭建win+mac】

一、硬件配配置要求 系统&#xff1a;windows 10 / Mac os 硬盘&#xff1a;C 盘预留 15GB 以上&#xff0c;其他盘 50GB 以上,Stable Ddiffusion的很多大模型都是以 GB 起步。 显卡&#xff1a;4GB 以上&#xff0c;建议 8GB, 效率高&#xff0c;能玩大尺寸的图 CPU&…

Socks IP轮换:为什么是数据挖掘和Web爬取的最佳选择?

在数据挖掘和Web爬取的过程中&#xff0c;IP轮换是一个非常重要的概念。数据挖掘和Web爬取需要从多个网站或来源获取数据&#xff0c;而这些网站通常会对来自同一IP地址的请求进行限制或封锁。为了避免这些问题&#xff0c;数据挖掘和Web爬取过程中需要使用Socks IP轮换技术。在…

Redis秒杀:一人一单问题及初步解决

优惠券秒杀一人一单 前言一、需求以及之前存在的问题二、增加一人一单逻辑1.初步代码2.封装一人一单逻辑3.控制锁的粒度 三、事务控制问题四、总结 前言 跟随黑马虎哥学习redis&#xff1a; 这是我认为b站上最好的redis教程&#xff0c;各方面讲解透彻&#xff0c;知识点覆盖…

Mr. Cappuccino的第53杯咖啡——Mybatis源码分析

Mybatis源码分析 Mybatis源码分析入口1. 读取配置文件总结 2. 解析配置文件核心代码&#xff08;一&#xff09;核心代码&#xff08;二&#xff09;分析parse()方法分析build()方法 总结 3. 获取SqlSession总结 4. 获取mapper代理对象总结 5. 使用mapper代理对象执行Sql语句二…

基于SpringBoot+Vue的会员制医疗预约服务管理信息系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

Android Studio log的快捷键和使用

输入logi&#xff0c;然后按下Tab键&#xff0c;会自动补全一条info级别的打印日志。输入logw&#xff0c;按下Tab键&#xff0c;会自动补全一条warn级别的打印日志&#xff0c;以此类推。 如下图所示&#xff1a;

C#项目发布

C#项目发布 vs code 打包iis 配置 vs code 打包 iis 配置

VMware Linux Centos 配置网络并设置为静态ip

在root用户下进行以下操作 1. 查看子网ip和网关 &#xff08;1&#xff09;进入虚拟网络编辑器 &#xff08;2&#xff09;进入NAT设置 &#xff08;3&#xff09;记录子网IP和子网掩码 2. 修改网络配置文件 &#xff08;1&#xff09;cd到网络配置文件路径下 [rootlo…

【视觉SLAM入门】5.1. 特征提取和匹配--FAST,ORB(关键点描述子),2D-2D对极几何,本质矩阵,单应矩阵,三角测量,三角化矛盾

"不言而善应" 0. 基础知识1. 特征提取和匹配1.1 FAST关键点1.2 ORB的关键点--改进FAST1.3 ORB的描述子--BRIEF1.4 总结 2. 对极几何&#xff0c;对极约束2.1 本质矩阵(对极约束)2.1.1 求解本质矩阵2.1.2 恢复相机运动 R &#xff0c; t R&#xff0c;t R&#xff0c;…

推荐几款小众且无广告的软件,你值得拥有

你是否喜欢一些小众且无广告的软件&#xff1f;如果是的话&#xff0c;我这边有一些给你推荐的。 护眼软件——EyeLoveU ​ EyeLoveU是一款免费的护眼软件&#xff0c;可以在你使用电脑一段时间后&#xff0c;提醒你该让眼睛休息。EyeLoveU是一种智能的眼睛保护程序&#xff…

python tkinker界面

import tkinter from PIL import Image, ImageTkdog tkinter.Tk() # 设置图片描绘的坐标&#xff0c;注意乘号是字母x dog.geometry(500x500200100) # 不允许修改大小 dog.resizable(False, False) # 不显示标题栏 dog.overrideredirect(True) # 设置白色透明色&#xff0c;这…

【玩转pandas系列】数据清洗(文末送书福利)

文章目录 一、重复值检测二、元素替换1️⃣ 元素替换replace2️⃣ 数据映射map 三、修改索引1️⃣ 修改索引名rename2️⃣ 设置索引和重置索引 四、数据处理1️⃣ apply与applymap2️⃣ transform 五、异常值处理六、抽样聚合函数1️⃣ 抽样2️⃣ 数学函数 七、分组聚合&#x…

DAY16_VUE基本用法详细版

目录 0 HBuilderX修改注释0 HBuilderX 修改.VUE中的注释颜色1 Vue入门1.1 什么是Vue1.2 Vue优点1.3 Vue案例1.3.1入门案例1.3.2 v-cloak属性1.3.3.1 v-text 指令1.3.3.2 v-html 指令1.3.3.3 v-pre 指令1.3.3.4 v-once 指令1.3.3.5 v-model 指令 1.3.4 MVVM思想 1.4 事件绑定1.4…

OpenLayers入门,OpenLayers如何加载WFS服务的要素资源数据

专栏目录: OpenLayers入门教程汇总目录 前言 本章讲解如何使用OpenLayers加载WFS服务的要素资源数据。 WFS规范介绍 WFS是基于地理要素级别的数据共享和数据操作,WFS规范定义了若干基于地理要素(Feature)级别的数据操作接口,并以 HTTP 作为分布式计算平台。通过 WFS服…