数据结构·单链表经典例题

1. 移除链表元素

        OJ链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

        本题是说给出一个链表的头节点head和一个整数val,如果发现节点中存的数据有val就删掉它,最后返回修改后的链表头节点地址

        如果题目中没有明确提及给出的链表是否是带头的,那就默认是不带头的链表,此时题目中再提到头节点就是指链表的第一个节点

思路1:

        从第二个节点开始,判断其内含的数据是否是val,然后遍历链表,最后判断头节点中数据是否是val,如果是,再挪移头节点的指向

        至于为什么从第二个节点开始扫描是为了不用每次都判断一下头节点要不要移动,先把后面的节点都处理好,最后再确定头节点的指向

        但是这个思路还是太复杂了

思路2:

        创建一个新链表,把不是val的节点都丢到新链表中去,最后返回新链表的头节点

        与其说是创建了一个新链表,不如说是将原链表的链接顺序拿到一个新的地方进行更改

struct ListNode* removeElements(struct ListNode* head, int val) 
{
    //记录新链表的头和尾
    struct ListNode* newhead = NULL;
    struct ListNode* newtail = NULL;
    //pcur用来扫描原链表
    struct ListNode* pcur = head;

    while (pcur)
    {
        //不是val尾插到新链表的尾
        if (pcur->val != val)
        {
            //如果新链表为空,那么新加入的节点既是头节点也是尾节点
            if (newhead == NULL)
            {
                newhead = pcur;
                newtail = pcur;
            }
            //如果链表不为空,就将新节点放到链表尾,
            else
            {
                newtail->next = pcur;
                newtail = pcur;
            }
        }
        //pcur指向的节点是不是val都要往下走
        pcur = pcur->next;
    }
    //因为有可能返回的是空链表,所以不能粗暴的去访问newtail->next
    //要先判断要返回的newtail是否为空,也就是说是否是空链表
    if (newtail)
    {
        newtail->next = NULL;
    }
    return newhead;
}

2. 链表的中间结点

        OJ链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

        本题是说,给出一个链表的头节点head,然后找到这个链表的中间节点,如果有两个中间节点,就返回第二个中间节点

思路1:

        遍历整个链表,数出一共有几个节点,然后通过除2找到中间节点的"下标",然后通过"下标",再访问出中间节点的地址

        很明显,这个方法很麻烦

思路2:快慢指针法

        跟前面双指针那节一样,这个快慢指针也不是真正的创造两个指针,而是创造两个具有类似指针功能的变量

        思路就是创造一个慢指针slow,一个快指针fast,然后slow走一步,fast走两步,这样fast走完的时候slow刚好来到链表中间

        快慢指针法就是通过只遍历一次就能达到对整体进行类似除法运算的功效,比如slow走1步fast走4步,fast走完,slow就走到整体的四分之一处

        回到本题,在判断结束扫描的条件时要注意,先判断fast是否为NULL,利用短路的特性避免判断fast->next,因为如果fast为假了,去访问next的时候就会崩

struct ListNode* middleNode(struct ListNode* head) 
{
	struct ListNode* slow = head;
	struct ListNode* fast = head;

	//有一个为假就跳出循环
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	return slow;
}

3. 反转链表

        OJ链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

        本体是说给一个单链表的头节点地址head,让反转链表,再将新链表的头返回,值得注意的是这个链表可能是个空链表

思路1:

        和第一题类似,创建一个"新链表",每次将旧链表的第一个节点拿下来,头插到新链表

        因为这题给的是单链表,不能用后面的节点访问前面的节点,所以不要想从最后一个节点开始改变链接方向,因为遍历到最后一个节点就找不到前面的节点了

思路2:

        用3个指针n1、n2、n3,初始状态n1指向空,n2指向头节点,n3指向第二个节点。然后将n2节点的指向变成n1,然后把n1变到n2的位置,n2变到n3的位置,再把n3滑到下一个节点。然后在n2不为空的情况下一直循环这个操作。

struct ListNode* reverseList(struct ListNode* head) 
{
    //如果传过来的是空链表
    if (head == NULL)
    {
        return head;
    }
    struct ListNode* n1 = NULL;
    struct ListNode* n2 = head;
    struct ListNode* n3 = head->next;

    while (n2)
    {
        n2->next = n1;
        n1 = n2;
        n3 = n2;
        //如果n3已经指向NULL了就不用往下滑了
        if (n3)
        {
            n3 = n3->next;
        }        
    }
    return n1;
}

4. 合并两个有序链表

        OJ链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

        本题是说,给两个升序链表的头节点地址list1和list2,然后将两个链表合并成一共新的升序链表,并返回新链表的头,值得注意的是给出的两个链表可能有空的

思路:

        创建一个"新链表",再用顺序表中讲到的那道合并数组的题的思想

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{
    //如果给出的某个链表为空,就返回另一个链表
    if (list1 == NULL)
    {
        return list2;
    }
    if (list2 == NULL)
    {
        return list1;
    }
    //两个扫描原链表的指针
    struct ListNode* p1 = list1;
    struct ListNode* p2 = list2;

    //两个控制新链表的指针
    struct ListNode* newhead = NULL;
    struct ListNode* newtail = NULL;

    //p1或p2有一个扫描完就退出循环
    while (p1 && p2)
    {
        //如果p1扫到的数据更小
        if (p1->val < p2->val)
        {
            //如果新链表中没有节点
            if (newhead == NULL)
            {
                newhead = p1;
                newtail = p1;
            }
            //如果新链表不为空
            else
            {
                newtail->next = p1;
                newtail = p1;
            }
            p1 = p1->next;
        }
        //如果p2扫到的数据更小
        else
        {
            //如果新链表为空
            if (newhead == NULL)
            {
                newhead = p2;
                newtail = p2;
            }
            //如果新链表不为空
            else
            {
                newtail->next = p2;
                newtail = p2;
            }
            p2 = p2->next;
        }
    }
    //处理旧链表没挪完的那部分
    if (p1)
    {
        newtail->next = p1;
    }
    if (p2)
    {
        newtail->next = p2;
    }
    return newhead;
}

5. 分割链表(带头链表的优势)

        本题我会距离说明带头链表比不带头链表好在哪里

        OJ链接:https://leetcode.cn/problems/partition-list-lcci/description/

        本题给出一个链表的头节点地址,和一个特定的值x,要求是把所存数据小于x的节点堆在前面,把大于等于x的节点堆在后面,堆放的时候不需要保存节点原来相对位置的有关信息

思路1:

        创建一个"新链表"把原链表中小于x的节点头插,把大于等于x的节点尾插

思路2:带头链表的优点

        先说解题思路,我们创造两个"新链表",lesshead尾插小于x的节点,bighead尾插大于等于x的节点,最后把bighead连到lesshead后面

        现在我们回忆一下,之前的代码再每次插入新节点的时候都要判断一下链表是否为空,这很麻烦。所以我们直接让链表带头,这样每次插入新节点的时候就不用判断了,因为链表一定不为空,它有一个不存储数据的头或者说"哨兵位",省去了插入时的很多麻烦

struct ListNode* partition(struct ListNode* head, int x) 
{
	//判断传过来的是否时空链表
	if (head == NULL)
	{
		return head;
	}

	//创建两个带头新链表
	struct ListNode* lesshead, * lesstail;
	struct ListNode* bighead, * bigtail;
	//申请头节点空间,并将其地址记录
	lesshead = lesstail = (struct ListNode*)malloc(sizeof(struct ListNode));
	bighead = bigtail = (struct ListNode*)malloc(sizeof(struct ListNode));

	//用pcur遍历原链表,将节点放到对应的新链表中
	struct ListNode* pcur = head;

	while (pcur)
	{
		if (pcur->val < x)
		{
			lesstail->next = pcur;
			lesstail = lesstail->next;
		}
		else
		{
			bigtail->next = pcur;
			bigtail = bigtail->next;
		}
		pcur = pcur->next;
	}
	//链接两个链表
	//先将大链表的尾置空
	bigtail->next = NULL;
	//再接上,注意要掠过大链表的那个没意义的头
	lesstail->next = bighead->next;
	//先存上小链表的第一个存有效数据的节点
	struct ListNode* ret = lesshead->next;
	//在释放两个新链表的头
	free(bighead);
	free(lesshead);

	return ret;
}

6. 环形链表的约瑟夫问题

        OJ链接:环形链表的约瑟夫问题_牛客题霸_牛客网

        本题······哎呀这题我就不复述了,人家题干说的挺清楚的

思路:循环链表

        创建不带头单向循环链表,模拟围成一圈的人,逢m就删除节点

#include<stdlib.h>
//创建新节点
struct ListNode* BuyNode(int x)
{
	struct ListNode* newnode = (struct ListNode*)malloc(sizeof(struct ListNode));
	newnode->val = x;
	newnode->next = NULL;
	return newnode;
}
//创建链表
struct ListNode* creatlist(int n)
{
	//先创建一个头节点
	struct ListNode* phead = BuyNode(1);
	struct ListNode* ptail = phead;
	//再循环进行尾插,形成链表
	for (int i = 2; i <= n; i++)
	{
		ptail->next = BuyNode(i);
		ptail = ptail->next;
	}
	//让链表首尾相连
	ptail->next = phead;
	return phead;
}

int ysf(int n, int m) 
{
	//创建不带头单向循环链表
	struct ListNode* phead = creatlist(n);
	struct ListNode* pcur = phead;
	struct ListNode* prev = NULL;
	//逢m删除节点,直到剩下最后一个节点
	int count = 1;
	while (pcur->next != pcur)
	{
		if (m == count)
		{
			//删除当前节点
			prev->next = pcur->next;
			free(pcur);
			count = 1;
			pcur = prev->next;
		}
		else
		{
			//pcur往后走
			prev = pcur;
			pcur = pcur->next;
			count++;
		}
	}
	return pcur->val;
}

        不必担心当 m==1 的使得 prev->next 非法的情况,while的循环条件就已经把这种情况挡在外面了,而且题干里说了一定会剩下来一个人,所以返回pcur的数据也是没有问题的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用vue实现微信小程序的点餐首页-纯前端效果

一、效果图 图片来源于网络 二、代码 <template><view class"container"><view class"top"><image src"../../static/img/home.png" class"home"></image></view><view class"content&…

Lucene 源码分析——BKD-Tree

Lucene 源码分析——BKD-Tree - AIQ Bkd-Tree Bkd-Tree作为一种基于K-D-B-tree的索引结构&#xff0c;用来对多维度的点数据(multi-dimensional point data)集进行索引。Bkd-Tree跟K-D-B-tree的理论部分在本篇文章中不详细介绍&#xff0c;对应的两篇论文在附件中&#xff0c…

【lodash.js】非常好用高性能的 JavaScript 实用工具库,防抖,深克隆,排序等

前言&#xff1a;lodash是一款前端必须要知道的js库&#xff0c;它里面提供了许多常用的功能和实用的工具函数 基本上我参与的项目中都有lodash&#xff0c;只能说lodash太强大了&#xff0c;lodash.js 提供了超过 300 个实用的工具函数&#xff0c;涵盖了很多常见的编程任务 l…

3D点云数据的标定,从搭建环境到点云标定方法及过程,只要有一台Windows笔记本,让你学会点云标定

ptscloudpre: 点云标定准备&#xff1a; 说明&#xff1a; 如下介绍适用windows系统的电脑。apple笔记本同理&#xff0c;但是需要安装MAC版本的anaconda。网址&#xff1a;Free Download | Anaconda可下载对应MAC版本的Anaconda的安装包建议下载2022年或2021年的安装包安装。…

华硕ASUS K43SD笔记本安装win7X64(ventoy为入口以支撑一盘多系统);友善之臂mini2440开发板学习

记录 老爷机 白色 华硕 K43SD 笔记本 安装 win7X64 1. MBR样式常规安装win7X64Sp1 (华硕 K43SD 安装 win7X64 ) 老爷机 白色 华硕 K43SD 笔记本 安装 win7X64 (常规安装) 设置: 禁用UEFI 启用AHCI ventoy制作MBR(非UEFI)方式的启动U盘 U盘中放cn_windows_7_ultimate_wit…

无限学模式-“重塑科研学习路径:ChatGPT应用实战课,开启高效率、高创新的科研之旅!“

ChatGPT 在论文写作与编程方面也具备强大的能力。无论是进行代码生成、错误调试还是解决编程难题&#xff0c;ChatGPT都能为您提供实用且高质量的建议和指导&#xff0c;提高编程效率和准确性。此外&#xff0c;ChatGPT是一位出色的合作伙伴&#xff0c;可以为您提供论文写作的…

YOLOv8全网独家首发:Powerful-IoU更好、更快的收敛IoU | 2024年最新IoU

💡💡💡本文独家改进:Powerful-IoU更好、更快的收敛IoU,是一种结合了目标尺寸自适应惩罚因子和基于锚框质量的梯度调节函数的损失函数 💡💡💡MS COCO和PASCAL VOC数据集实现涨点 收录 YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.htm…

SkyWalking介绍与使用docker-compose部署服务

一、Skywalking概述 1、Skywalking介绍 Skywalking是分布式系统的应用程序性能监视工具,专为微服务,云原生架构和基于容器(Docker,K8S,Mesos)架构而设计,它是一款优秀的APM(Application Performance Management)工具,包括了分布式追踪,性能指标分析和服务依赖分析等…

腾讯云轻量应用服务器Docker如何一键搭建属于自己的幻兽帕鲁服务器?

幻兽帕鲁/Palworld是一款2024年Pocketpair开发的开放世界生存制作游戏&#xff0c;在帕鲁的世界&#xff0c;玩家可以选择与神奇的生物“帕鲁”一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。而帕鲁可以进行战斗、繁殖、协助玩家做农活&#xff0c;也…

【Image captioning】论文阅读七—Efficient Image Captioning for Edge Devices_AAAI2023

中文标题:面向边缘设备的高效图像描述(Efficient Image Captioning for Edge Devices) 文章目录 1. 引言2. 相关工作3. 方法3.1 Model Architecture(模型结构)3.2 Model Training (模型训练)3.3 Knowledge Distillation (知识蒸馏)4. 实验4.1 数据集和评价指标4.2 实施细…

【快影】怎么制作卡拉OK字幕

您好&#xff0c;您添加了字幕之后可以添加动画&#xff0c;选择卡拉OK&#xff0c;其中 卡拉OK1是支持修改颜色的&#xff0c;卡拉OK2只支持修改文字的底色。

Apache Shiro 安全框架

前言 Apache Shiro 是一个强大且容易使用的Java安全矿建&#xff0c;执行身份验证&#xff0c;授权&#xff0c;密码和会话管理。使用Shiro的易于理解的API您可以快速轻松的获得任何应用程序直到大的项目。 一丶什么是Shiro 1.Shiro是什么 Apache Shiro是一个强大且易于使用…

5.列表选择弹窗(BottomListPopup)

愿你出走半生,归来仍是少年&#xff01; 环境&#xff1a;.NET 7、MAUI 从底部弹出的列表选择弹窗。 1.布局 <?xml version"1.0" encoding"utf-8" ?> <toolkit:Popup xmlns"http://schemas.microsoft.com/dotnet/2021/maui"xmlns…

防火墙在企业园区出口安全方案中的应用(ENSP实现)

拓扑图 需求&#xff1a; 1、企业出口网关设备必须具备较高的可靠性&#xff0c;为了避免单点故障&#xff0c;要求两台设备形成双机热备状态。当一台设备发生故障时&#xff0c;另一台设备会接替其工作&#xff0c;不会影响业务正常运行。 2、企业从两个ISP租用了两条链路&…

【QT】二进制文件读写

目录 1 实例功能概述 2 Qt预定义编石马文件的读写 2.1 保存为文件 2.2 stm文件格式 2.3 读取stm文件 3 标准编码文件的读写 3.1 保存为dat文件 3.2 dat文件格式 3.3 读取dat文件 文件的读写是很多应用程序具有的功能&#xff0c;甚至某些应用程序就是围绕着某一种格式文件的处 …

[docker] Docker的数据卷、数据卷容器,容器互联

一、数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中。可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立刻可见&#xff0c;并且更新数据不会影响镜像&#xff0c;从而实现数据在宿主机与容…

开发知识点-Flutter移动应用开发

支持 安卓 IOS Android 鸿蒙 第一章dart基础章节介绍 移动电商——Flutter-广告Banner组件制作 移动电商——Flutter实战课程介绍 Flutter实例——路由跳转的动画效果

禅道(HIS医疗系统)项目管理

文章目录 前言禅道的基本使用指南本次讲解举例参与人员&#xff1a;一、admin管理组织结构1.1批量新增用户 二、产品经理使用禅道2.1以陈雪燕账号去创建产品2.2添加产品模块2.3添加产品计划2.4添加产品需求2.5创建项目4.6设置团队 三、项目经理使用禅道3.1关联需求3.2分解任务 …

【寒假每日一题·2024】AcWing 4965. 三国游戏(补)

文章目录 一、题目1、原题链接2、题目描述 二、解题报告1、思路分析2、时间复杂度3、代码详解 一、题目 1、原题链接 4965. 三国游戏 2、题目描述 二、解题报告 1、思路分析 思路参考y总&#xff1a;y总讲解视频 &#xff08;1&#xff09;题目中的获胜情况分为三种&#xff…

【Servlet】如何编写第一个Servlet程序

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Servlet】 本专栏旨在分享学习Servlet的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; Servlet是Java编写的服务器端…
最新文章