【数据结构】链表练习题(1)

news2024/11/25 9:48:27

练习题

  • 1.移除链表元素(LeetCode203)
  • 2.链表的中间结点(LeetCode876)
  • 3.链表的倒数第k个结点(剑指offer)
  • 4.反转链表(LeetCode206)
  • 5.合并两个有序链表(LeetCode21)
  • 6.链表分割(牛客)
  • 7.链表的回文结构(牛客)


1.移除链表元素(LeetCode203)

给你一个链表的头结点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头结点 。OJ链接

在这里插入图片描述
思路
创建一个新链表,把不等于val的结点尾插到新链表。

代码

struct ListNode 
{
	int val;
	struct ListNode* next;	
};
struct ListNode* removeElements(struct ListNode* head, int val)
{
	struct ListNode* NewHead = NULL;//创建一个新的头结点
	struct ListNode* cur = head;//用来遍历整个链表
	struct ListNode* tail = NULL;//指向新链表的最后一个结点,用来尾插数据
	while (cur)
	{
		if (cur->val == val)//相等就把这个结点释放
		{
			struct ListNode* tmp = cur->next;//储存下一个结点的地址,防止节点释放后找不到下一个结点
			free(cur);
			cur = tmp;
		}
		else
		{
			if (NewHead == NULL)//将头结点指向不等于val的第一个元素
			{
				NewHead = tail = cur;
			}
			else
			{
				tail->next = cur;//尾插新结点
				tail = tail->next;//指向新链表的最后一个结点
			}
			cur = cur->next;
		}
	}
	if (tail)//如果最后一个结点刚好是val,那就tail指向的下一个结点置为NULL
	{        //如果链表是空,也不会进行对NULL的访问
		tail->next = NULL;
	}
	return NewHead;
}

结果
在这里插入图片描述


2.链表的中间结点(LeetCode876)

给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。OJ链接
在这里插入图片描述
思路
常规思路就是遍历整个链表,得到链表的结点个数从而得到中间结点的下标,再遍历链表找到并返回这个结点。但在介绍一个牛逼的方法:快慢指针,慢指针每次循环走一步,快指针每次循环走两步,最终如果链表长度是奇数,快指针指向链表的最后一个结点,慢指针刚好指向中间结点,如果链表长度是偶数,快指针指向最后一个结点指向的NULL,慢指针指向两个中间结点的第二个结点。
代码

struct ListNode 
{
	int val;
	struct ListNode* next;
};
struct ListNode* middleNode(struct ListNode* head) 
{
	struct ListNode* slow = head, * fast = head;
	while (fast != NULL && fast->next != NULL)//用&&是因为只要有一个不满足就停止循环
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	return slow;
}

结果
在这里插入图片描述


3.链表的倒数第k个结点(剑指offer)

输入一个链表,输出该链表中倒数第k个结点。OJ链接
在这里插入图片描述
思路
还是用快慢指针的方法。要求倒数第k个,快指针就先走k步,此时快指针和慢指针之间的距离为k步,然后和满指针每次走一步,当快指针指向NULL,慢指针和快指针的距离是k步,慢指针和最后一个结点的距离是k-1步,慢指针刚好是倒数第k个结点。
代码

struct ListNode 
{
	int val;
	struct ListNode* next;
};
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k) {
    struct ListNode* slow, * fast = NULL;
    slow = fast = pListHead;
    while (k--)//fast先走k步
    {
        if (fast == NULL)//走出链表,就直接返回NULL
        {
            return NULL;
        }
        fast = fast->next;
    }
    //此时fast与slow的距离是k,当fast指向NULL,
    //slow与最后一个节点的距离就是k-1,slow就是倒数第k个
    while (fast)
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

结果
在这里插入图片描述


4.反转链表(LeetCode206)

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。OJ链接
在这里插入图片描述
思路
法1利用三个指针(n1,n2,n3)实现逆序,n2指向当前结点,n3指向下一个结点,n1指向上一个结点。如图。
在这里插入图片描述

法2创建一个新的链表,取出要逆序链表的节点头插到新链表。
在这里插入图片描述
代码

//法1
struct ListNode 
{
    int val;
    struct ListNode* next;
    
};
struct ListNode* reverseList(struct ListNode* head)
{
    if (head == NULL)//检查是否为空
    {
        return NULL;
    }
    struct ListNode* n1 = NULL,*n2 =head,*n3 =head->next;
    while (n2)//一旦n2指向NULL就停止循环
    {
        n2->next = n1;
        n1 = n2;
        n2 = n3;
        if (n3)//防止n3越界访问,一旦n3指向NULL,就不再改变
        {
            n3 = n3->next;
        }
    }
    return n1;
}
//法2
struct ListNode 
{
    int val;
    struct ListNode* next;
    
};
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* newHead = NULL;
    struct ListNode* cur = head;//遍历链表
    while (cur)
    {
        struct ListNode* next = cur->next;//记住下一个结点
        cur->next = newHead;//指向头结点指向的结点
        newHead = cur;
        cur = next;
    }
    return newHead;//不用检查链表为空,因为为空不进入循环,返回NULL
}

结果
在这里插入图片描述


5.合并两个有序链表(LeetCode21)

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。OJ链接在这里插入图片描述
思路
创建一个新链表,以此比较两个升序链表的结点,取小的结点尾插。如图。在这里插入图片描述
代码

struct ListNode 
{
	int val;
	struct ListNode* next;
	
};
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
	struct ListNode* cur1 = list1, * cur2 = list2;//分别遍历两个链表
	struct ListNode* head = NULL,*tail = head;//head是新链表的头结点,tail指向新链表的最后一个结点,方便尾插
	if (list1 == NULL)//如果有链表为空,返回另一个链表
	{
		return list2;
	}
	if (list2 == NULL)
	{
		return list1;
	}
	while (cur1 && cur2)//有一个是NULL就结束循环
	{
		if (cur1->val < cur2->val)
		{
			if (head == NULL)//考虑到第一次插入节点
			{
				head = tail = cur1;
			}
			else
			{
				tail->next = cur1;
				tail = tail->next;
				cur1 = cur1->next;//cur1还指向原来链表的下一个结点,所以不用用指针记录下一个结点
			}
		}
		else
		{
			if (head == NULL)//考虑到第一次插入节点
			{
				head = tail = cur2;
			}
			else
			{
				tail->next = cur2;
				tail = tail->next;
				cur2 = cur2->next;//cur1还指向原来链表的下一个结点,所以不用用指针记录下一个结点
			}
		}
	}
	if (cur1 == NULL)//说明list2还有结点,直接插到新链表的尾部即可
	{
		tail->next = cur2;
	}
	if (cur2 == NULL)
	{
		tail->next = cur1;
	}
	return head;
}

结果
在这里插入图片描述


6.链表分割(牛客)

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。OJ链接
思路
把小于x的结点插到一个链表,大于或等于x的结点插到另一个链表,然后把两个链表链接起来。
预备知识
在使用单链表时,我们通常用用一个指针指向第一个结点,作为头结点,而这道题得使用哨兵位的头结点,用一个结点来指向链表的第一个结点。什么是哨兵位的头结点?顾名思义就是一个结点,这个结点不存储数据,只指向第一个结点,至于它的作用后面会讲到,现在只需知道它是一个不存储数据的、指向第一个结点的结点
在这里插入图片描述

代码

struct ListNode {
    int val;
    struct ListNode* next;
};
struct ListNode* partition(struct ListNode* pHead, int x)
{
    struct ListNode* smallGuard = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* bigGuard = (struct ListNode*)malloc(sizeof(struct ListNode));
    smallGuard->next = NULL;
    bigGuard->next = NULL;
    struct ListNode* smallTail = smallGuard, * bigTail = bigGuard, * cur = pHead;
    while (cur)
    {
        if (cur->val < x)
        {
            smallTail->next = cur;
            smallTail = smallTail->next;
        }
        else
        {
            bigTail->next = cur;
            bigTail = bigTail->next;
        }
        cur = cur->next;
    }
    smallTail->next = bigGuard->next;//将大链表链接到另一个链表,
    bigTail->next = NULL;//同时记得将大链表的最后一个节点指向NULL,防止其指向链表的另一个节点,导致环形链表
    pHead = bigGuard->next;//将新链表的头节点赋值给phead,因为哨兵位的头节点要释放
    free(bigGuard);
    free(smallGuard);
    bigGuard = NULL;
    smallGuard = NULL;
    return pHead;
}

结果
在这里插入图片描述

哨兵位头节点的作用
在这里插入图片描述


7.链表的回文结构(牛客)

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
在这里插入图片描述
思路
先找到中间节点(可以用前面的函数),从中间节点开始,对后半段进行逆序(用前面的函数),最后判断前半段和后半段是否相等。
在这里插入图片描述

代码

struct ListNode {
    int val;
    struct ListNode* next;
};
struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* slow, * fast;
    slow = fast = head;
    while ((fast != NULL) && (fast->next != NULL)) {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* newHead = NULL;
    struct ListNode* cur = head;
    while (cur) {
        struct ListNode* next = cur->next;
        cur->next = newHead;
        newHead = cur;
        cur = next;
    }
    return newHead;
}
bool chkPalindrome(struct ListNode* head)
{
    struct ListNode* mid = middleNode(head);
    struct ListNode* rhead = reverseList(head);
    while (rhead && head)//当有偶数个节点时,rhead先遇到NULL,当有奇数个节点时,head和rhead同时遇到NULL
    {
        if (rhead->val != head->val)
        {
            return false;
        }
    }
    return true;
}

结果
在这里插入图片描述


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

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

相关文章

第十四届蓝桥杯三月真题刷题训练——第 4 天

目录 题目 1 &#xff1a;九数算式_dfs回溯(全排列) 题目描述 运行限制 代码&#xff1a; 题目2&#xff1a;完全平方数 问题描述 输入格式 输出格式 样例输入 1 样例输出 1 样例输入 2 样例输出 2 评测用例规模与约定 运行限制 代码&#xff1a; 题目 1 &am…

数据结构刷题(十九):77组合、216组合总和III

1.组合题目链接过程图&#xff1a;先从集合中取一个数&#xff0c;再依次从剩余数中取k-1个数。思路&#xff1a;回溯算法。使用回溯三部曲进行解题&#xff1a;递归函数的返回值以及参数&#xff1a;n&#xff0c;k&#xff0c;startIndex(记录每次循环集合从哪里开始遍历的位…

场景式消费激发春日经济,这些电商品类迎来消费热潮

春日越临近&#xff0c;商机越浓郁。随着气温渐升&#xff0c;春日经济已经潜伏在大众身边。“春菜”、“春装”、“春游”、“春季养生”等春日场景式消费走热。 下面&#xff0c;鲸参谋为大家盘点几个与春日经济紧密相关的行业。 •春日仪式之春游踏青 ——户外装备全面开花…

查看 WiFi 密码的两种方法

查看 WiFi 密码的两种方法1. 概述2. 在控制面板中查看 WiFi 密码3. 使用 CMD 查看 WiFi 密码结束语1. 概述 突然忘记 WiFi 密码怎么办&#xff1f; 想连上某个使用过的 WiFi&#xff0c;但有不知道 WiFi 密码怎么办&#xff1f; 使用电脑如何查询 WiFi 密码&#xff1f; 以下是…

zabbix4.0 网络发现-自动添加主机-自动注册

zabbix的网络发现 网络发现的好处&#xff1a; 加快zabbix部署 简化管理 无需过多管理就能在快速变化的环境中使用zabbix zabbix网络发现给予以下信息 IP范围 可用的外部服务&#xff08;FTP&#xff0c;SSH&#xff0c;WEB&#xff0c;POP3&#xff0c;IMAP&#xff0c;TCP等&…

一篇深入解析BTF 实践指南

BPF 是 Linux 内核中基于寄存器的虚拟机&#xff0c;可安全、高效和事件驱动的方式执行加载至内核的字节码。与内核模块不同&#xff0c;BPF 程序经过验证以确保它们终止并且不包含任何可能锁定内核的循环。BPF 程序允许调用的内核函数也受到限制&#xff0c;以确保最大的安全性…

FPGA使用GTX实现SFP光纤收发SDI视频 全网首创略显高端 提供工程源码和技术支持

目录1、前言2、设计思路和框架3、vivado工程详解4、上板调试验证并演示5、福利&#xff1a;工程代码的获取1、前言 FPGA实现SDI视频编解码目前有两种方案&#xff1a; 一是使用专用编解码芯片&#xff0c;比如典型的接收器GS2971&#xff0c;发送器GS2972&#xff0c;优点是简…

如何让网络安全的防守技术更强?20年白帽子老江湖告诉你【蓝队】

网络安全的防守技术是网络安全工程师必备技能&#xff0c;只有攻防兼备的白帽子&#xff0c;才算是真正的网安精英。 网络安全的攻击技术在前面我已经讲过了&#xff0c;感兴趣的可以去看看&#xff1a; 90%的人都不算会网络安全&#xff0c;这才是真正的白帽子技术【红队】 . …

蓝桥杯--成绩分析

成绩分析 技巧 求最大值与最小值 if(a[i]>max) maxa[i]; if(a[i]<min) mina[i]; 这里的max为最小值0 这里的min为最大值100 这道题比较简单 题目大意 小蓝给学生们组织了一场考试&#xff0c;卷面总分为 100 分&#xff0c;每个学生的得分都是一个 0 到 100 的整数。 请…

【GO】K8s 管理系统项目33[前端部分–登录和登出]

K8s 管理系统项目[前端部分–登录和登出] 1. 登录登出流程 1.1 登录流程 登入流程总的分为5步: 账号密码验证token生成token验证验证成功进行跳转验证失败返回/login 1.2 登出流程 登出流程就相对简单,分为2步 删除Token跳转/login 2. 登录代码 src/views/login/Login.v…

vue双向绑定原理

Vue双向绑定的原理 vue的双向绑定原理&#xff1a;vue数据的双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。其核心就是通过obj.defineProperty()方法来实现数据的劫持&#xff0c;在数据变化时发布消息给订阅者&#xff0c;触发相应的监听回调。也就是说数据和视…

windows安装Stable Diffusion WebUI及问题解决记录

本文将详细介绍stable diffusion webui的下载、安装及问题解决。 StableDiffusion是2022年发布的深度学习文本到图像生成模型。它主要用于根据文本的描述产生详细图像&#xff0c;尽管它也可以应用于其他任务&#xff0c;如内补绘制、外补绘制&#xff0c;以及在提示词​&#…

AUTOSAR知识点Com(五):CANIf模式PUD Channel

1、概述 每个L-PDU分配给一个专用的物理CAN通道&#xff0c;该通道连接CAN控制器和CAN网络。通过这种方式&#xff0c;所有属于物理通道的L-PDU都可以在处理逻辑上&#xff0c;单一的L-PDU通道组上进行控制。这些逻辑组表示ECU连接到底层CAN网络的所有I-PDU。图 展示了L-PDU信道…

category排序专辑

case1——对有限类型的字段按指定要求排序&#xff1a; #学历分布 xueli_tsdf.pivot_table(index学历,values教师id,aggfunccount,marginsTrue,margins_name总计) xueli_ts[占比]np.round(xueli_ts[教师id]/xueli_ts.loc[总计,教师id],2) xueli_ts.reset_index(inplaceTrue)xu…

Adding Conditional Control to Text-to-Image Diffusion Models

安全验证 - 知乎知乎&#xff0c;中文互联网高质量的问答社区和创作者聚集的原创内容平台&#xff0c;于 2011 年 1 月正式上线&#xff0c;以「让人们更好的分享知识、经验和见解&#xff0c;找到自己的解答」为品牌使命。知乎凭借认真、专业、友善的社区氛围、独特的产品机制…

Java要学到什么程度才能找工作?小白怎么去面试Java岗位?

作为一个Java初学者&#xff0c;到底要学哪些知识点才能找到月薪过万的工作&#xff1f;或者说&#xff0c;怎样才能适应企业的开发流程&#xff0c;不至于进了公司都不知道怎么把需求转换成代码。甚至&#xff0c;唯唯诺诺的加班&#xff0c;一点自信都没有。本期文章&#xf…

STM32开发(18)----CubeMX配置RTC

CubeMX配置RTC前言一、什么是RTC&#xff1f;RTC时钟源RTC备份域二、实验过程1.CubeMX配置2.代码实现3.实验结果总结前言 本章介绍使用STM32CubeMX对RTC进行配置的方法&#xff0c;RTC的原理、概念和特点&#xff0c;配置各个步骤的功能&#xff0c;并通过实验方式验证。 一、…

Linux常见漏洞修复

一、nginx 修复TLS1.0&#xff0c;TLS1.1协议漏洞 1、漏洞描述 服务端口漏洞名称加固建议nginx443TLS版本1.0协议检测启用对TLS 1.2或1.3的支持&#xff0c;并禁用对TLS 1.0的支持。nginx443TLS版本1.1协议检测启用对TLS 1.2或1.3的支持&#xff0c;并禁用对TLS 1.1的支持。 …

Linux27 -- 通过抓包观察三次握手和四次挥手、链接的状态(tcp状态转移图)、TIME_WAIT 存在的原因

tcp协议的特点&#xff1a; 面向连接的&#xff0c;可靠的&#xff0c;流式服务 //面试常问&#xff1a; 一、通过抓包观察三次握手、四次挥手 工具&#xff1a;tcpdump 命令 抓冲我到他从他到我的数据包。 需要管理员权限。 运行示例&#xff1a; 进入管理员权限&#xff…

使用Advanced Installer打包程序及运行环境

Advanced Installer 工具版本&#xff1a;20.1.1 设置产品信息 选中右侧【Product Details】输入产品信息 设置文件和文件夹 添加使用VS发布之后的程序文件夹 设置文件夹刷新 选中文件夹&#xff0c;右键选择属性&#xff0c;选中Synchronize标签。启用“Synchronize conten…