【数据结构与算法】:10道链表经典OJ

1. 移除链表元素

在这里插入图片描述
思路1:遍历原链表,将 val 所在的节点释放掉。(太麻烦)

思路2:创建新链表,再遍历原链表,找到不为 val 的节点尾插到新链表。

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/342214109d444655a6081115428b345c.png

思路1代码实现如下:

注意:
1.当链表为空时,直接返回NULL即可。
2.当尾插上最后一个有效节点时,此时它的 next 可能还与最后一个节点相链接,一定要断开!


typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {if (head == NULL)return NULL;//创建一个新链表ListNode* newHead, * newTail;newHead = newTail = NULL;ListNode* pcur = head;//遍历原链表,找不为val的节点尾插while (pcur){ListNode* next = pcur->next;if (pcur->val != val){//没有一个节点if (newHead == NULL){newHead = newTail = pcur;}else{//有一个节点以上newTail->next = pcur;newTail = newTail->next;}}pcur = next;}if (newTail)newTail->next = NULL;return newHead;}

2. 反转链表

在这里插入图片描述

2.1反转指针法

思路:定义三个变量 n1,n2,n3,根据它们的指向关系进行迭代。
在这里插入图片描述

代码实现如下:

注意:
1.当链表为空时,直接返回NULL即可。
2.在迭代过程中别忘记判断 n3 ,防止对空指针解引用。
3.注意循环结束的条件,当 n2 为空时,n1 指向反转后的头,此时循环结束。

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {if (head == NULL)return NULL;ListNode* n1, * n2, * n3;n1 = NULL, n2 = head, n3 = n2->next;while (n2){n2->next = n1;n1 = n2;n2 = n3;if (n3)n3 = n3->next;}return n1;
}

2.2 头插法

思路:创建一个新链表,遍历原链表,依次取下原链表的每一个节点头插到新链表中。

代码实现如下:

注意:
1.当链表为空时,直接返回NULL即可。
2.头插时可以不用判断没有节点和有节点的情况。


typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {if (head == NULL)return NULL;ListNode* newHead, * newTail;newHead = newTail = NULL;ListNode* pcur = head;//一个一个拿下来头插while (pcur){ListNode* next = pcur->next;pcur->next = newHead;newHead = pcur;pcur = next;}return newHead;
}

3. 合并两个有序链表

在这里插入图片描述

思路:创建一个带哨兵位的新链表,遍历两个原链表,比较两个节点的值,哪个小就先尾插到新链表中。

代码实现如下:

注意:
1.当其中一个链表为空时,返回另一个链表即可。
2.创建哨兵位节点,方便尾插。
3.注意循环结束条件,当其中有一个链表走完时,跳出循环。
4.剩下的没走完的那个链表直接链接到后面。不需要用循环链接,因为它们本来就是连在一起的。
5.别忘记释放释放哨兵位节点,释放前要保存下一个节点。


typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {ListNode* n1, * n2;n1 = list1;n2 = list2;if (n1 == NULL)return n2;if (n2 == NULL)return n1;//创建哨兵位节点ListNode* phead = (ListNode*)malloc(sizeof(ListNode));ListNode* newHead, * newTail;newHead = newTail = phead;while (n1 && n2){//比较两个链表中数据的大小,谁小就先尾插到新链表if (n1->val < n2->val){newTail->next = n1;n1 = n1->next;newTail = newTail->next;}else{newTail->next = n2;n2 = n2->next;newTail = newTail->next;}}if (n1)newTail->next = n1;if (n2)newTail->next = n2;ListNode* ret = newHead->next;free(newHead);return ret;}

4. 分隔链表

在这里插入图片描述

思路:创建两个带哨兵位的新链表 less 和 greater 。遍历原链表,把小于x 的节点尾插到 less 链表中,把大于等于x 的节点尾插到greater 链表中。最后把 less 链表中的尾结点的 next 链接到 greater链表中的头结点上。

在这里插入图片描述

代码实现如下:

注意:
1.当链表尾空时,直接返回NULL即可。

2.有可能存在greater 链表中的最后一个结点与原链表中的最后一个结点仍然相链接的情况,一定要断开!


typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x) {if (head == NULL)return NULL;ListNode* lessHead, * lessTail, * greaterHead, * greaterTail;ListNode* pcur = head;//创建哨兵位节点,方便尾插lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));lessTail->next = NULL;greaterTail->next = NULL;while (pcur){if (pcur->val < x){lessTail->next = pcur;lessTail = lessTail->next;}else{greaterTail->next = pcur;greaterTail = greaterTail->next;}pcur = pcur->next;}lessTail->next = greaterHead->next;greaterTail->next = NULL;return lessHead->next;}

5. 环形链表

在这里插入图片描述

这是一个非常经典的例题,它要用上一种非常经典的算法:快慢指针法

定义一个 slow 变量,fast 变量,从链表的头结点开始,slow 每次走一步,fast 每次走两步,当 slow 进入环中时,fast 开始追逐。若成环,则必会在环内的某处相遇,否则 fast 或是 fast->next 最后会走到NULL。

代码实现如下:

注意:
1.当链表节点个数为偶数个时,若不成环,最终 fast == NULL。
当链表节点个数为奇数个时,若不成环,最终 fast->next == NULL.

2.循环条件 fast && fast->next 的位置不能交换。因为当为偶数个节点,fast走到NULL时,如果是 fast->next && fast ,那就是先执行 fast->next ,对空指针解引用,错误!!


typedef struct ListNode ListNode;
bool hasCycle(struct ListNode* head) {ListNode* slow, * fast;slow = fast = head;while (fast && fast->next){slow = slow->next;fast = fast->next->next;if (fast == slow)return true;}return false;
}

6. 链表的中间节点

在这里插入图片描述

也要用快慢指针法。也要分两种情况:
在这里插入图片描述

代码实现如下:

注意:
循环条件 fast && fast->next 的位置不能交换。因为当为偶数个节点,fast走到NULL时,如果是 fast->next && fast ,那就是先执行 fast->next ,对空指针解引用,错误!!


typedef struct ListNode ListNode;struct ListNode* middleNode(struct ListNode* head) {ListNode* slow = head;ListNode* fast = head;while (fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;}

7. 链表中倒数第K个节点

在这里插入图片描述

思路:
(1) fast 先走 k 步;
(2) slow 和 fast 再一起走,当 fast == NULL 时,slow 就是倒数第 k 个节点。

代码实现如下:

注意:
当 k 大于链表长度时,fast 会走到 NULL ,不能对空指针解引用,直接返回 NULL。


typedef struct ListNode ListNode;
struct ListNode* FindKthToTail(struct ListNode* pHead, int k ) {ListNode* fast ,*slow;fast = slow = pHead;//fast先走K步while(k--){//K大于链表长度时,直接返回NULLif(fast == NULL){return NULL;}fast = fast->next;}//再两者一起走while(fast){fast = fast->next;slow = slow->next;}return slow;}

8. 相交链表

在这里插入图片描述
首先要明确什么是相交链表:
在这里插入图片描述

思路1:暴力求解,时间复杂度O(N*N)
依次取A链表中的每个节点跟B链表中的所有节点比较。如果有相同地址的节点,则相交,第一次相同地址的节点就是交点,否则就不相交。

思路2:时间复杂度O(N)
(1) 先找到两个链表的尾,同时计算出两个链表的长度;
(2) 求出长度差;
(3) 判断哪个是长链表;
(4) 让长链表先走长度差步;
(5) 最后长短链表一起走,直到找到交点。

思路2代码实现如下:

注意:
要注意步骤(3)中判断长短链表的巧妙方法。可以避免写重复代码。

typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {ListNode* TailA,*TailB;TailA = headA;TailB = headB;//找尾同时计算长度int lenA = 0;int lenB = 0;while(TailA->next){TailA = TailA->next;lenA++;}while(TailB->next){TailB = TailB->next;lenB++;}//不相交if(TailA != TailB){return NULL;}//求出长度差int gap = abs(lenA - lenB);//判断哪个是长链表ListNode* longList = headA;//先默认A是长链表ListNode* shortList = headB;if(lenA < lenB){shortList = headA;longList = headB;}//让长链表走长度差步while(gap--){longList = longList->next;}//最后长短链表一起走,找交点while(longList != shortList){longList = longList->next;shortList = shortList->next;}return longList;}

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

在这里插入图片描述

在这里插入图片描述

思路:
首先要创建一个循环链表,定义一个计数器 count 用于数数,再遍历循环链表,当结点的 val == count 时,就"杀死",即销毁该节点。

代码实现如下:

注意:
要学习创建循环链表的方法!

typedef struct ListNode ListNode;//创建节点ListNode* BuyNode(int x){ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if(newnode == NULL){exit(-1);}newnode->val = x;newnode->next = NULL;return newnode;}//1.创建循环链表ListNode* Createnodecircle(int n){ListNode* phead = BuyNode(1);ListNode* ptail = phead;for(int i=2;i<=n;i++){ptail->next = BuyNode(i);ptail = ptail->next;}//尾连头,成环ptail->next = phead;return ptail;}int ysf(int n, int m ) {ListNode* prev = Createnodecircle(n);ListNode* pcur = prev->next;//开始数数int count = 1;while(pcur->next!=prev->next){if(count == m){prev->next = pcur->next;free(pcur);pcur = prev->next;count = 1;}else{prev = pcur;pcur = pcur->next;count++;}}return pcur->val;}

10. 链表的回文结构

在这里插入图片描述

这个题在牛客网中不能用C语言实现,我们可以选C++,因为C++是兼容C的,在C++中可以使用C的语法。

在这里插入图片描述

思路:
(1) 找到链表的中间节点;
(2) 把中间节点后面的链表进行逆置;
(3) 最后把逆置后的链表的值与中间节点之前的链表的值进行比较,若所有节点相等,则是回文链表,否则不是。有一个链表结束则比较结束。

代码实现如下:

注意:
逆置完之后,中间节点与前一个结点的链接可以不用断开,因为就算链接在一起也不影响判断。若强行断开,徒增麻烦。


//找中间结点
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;}//对中间结点之后的链表进行逆置
struct ListNode* reverseList(struct ListNode* head) {if (head == NULL)return NULL;struct ListNode* n1, * n2, * n3;n1 = NULL, n2 = head, n3 = n2->next;while (n2){n2->next = n1;n1 = n2;n2 = n3;if (n3)n3 = n3->next;}return n1;
}class PalindromeList {public:bool chkPalindrome(ListNode* A) {struct ListNode* mid = middleNode(A);struct ListNode* rHead = reverseList(mid);struct ListNode* curA = A;struct ListNode* curR = rHead;//把逆置后的链表与中间结点之前的链表进行比较while(curA && curR){if(curA->val != curR->val){return false;}else{curA = curA->next;curR = curR->next;}}return true;}};

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

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

相关文章

Pytorch: 利用预训练的残差网络ResNet50进行图像特征提取,并可视化特征图热图

1. 残差网络ResNet的结构 2.图像特征提取和可视化分析 import cv2 import time import os import matplotlib.pyplot as plt import torch from torch import nn import torchvision.models as models import torchvision.transforms as transforms import numpy as npimgname…

syscall的检测与绕过

普通调用 #include <iostream> #include <windows.h>int main() {unsigned char shellcode[] "";void* exec VirtualAlloc(0, sizeof shellcode, MEM_COMMIT,PAGE_EXECUTE_READWRITE);memcpy(exec, shellcode, sizeof shellcode);CreateThread(NULL, …

mybaits(8)-缓存机制

缓存机制 1、mybatis缓存2、一级缓存2.1 开启一级缓存2.2 一级缓存失效 3、二级缓存3.1 开启二级缓存3.2 二级缓存什么时候失效3.3 二级缓存的相关配置 4、MyBatis集成EhCache 1、mybatis缓存 缓存&#xff1a;cache 缓存的作用&#xff1a;通过减少IO的方式&#xff0c;来提高…

2024妈妈杯mathorcup数学建模C题 物流网络分拣中心货量预测及人员排班

一、数据预处理 数据清洗是指对数据进行清洗和整理&#xff0c;包括删除无效数据、缺失值填充、异常值检测和处理等。数据转换是指对数据进行转换和变换&#xff0c;包括数据缩放、数据归一化、数据标准化等。数据整理是指对数据进行整理和归纳&#xff0c;包括数据分组、数据聚…

PDF转TXT ChatGPT编程

1.目的 在Z-library找到一本书&#xff0c;只不过是PDF格式的&#xff0c;看的时候体验不好&#xff0c;还没有办法保存记录&#xff0c;就想着能不能转成txt格式放到手机自带的小说软件中看。 不想去网上找相关的软件&#xff0c;可以还需要付钱&#xff0c;所以尝试用ChatGP…

springcloud-fegin 组件调用

一、Feign 概述 Feign是Netflix开发的声明式、模板化的HTTP客户端&#xff0c; Feign可以帮助我们更快捷、优雅地调用HTTP API。 在Spring Cloud中&#xff0c;使用Feign非常简单——创建一个接口&#xff0c;并在接口上添加一些注解&#xff0c;代码就完成了。Feign支持多种…

R: 支持向量机(Support Vector Machine,简称SVM)

在数据科学和机器学习领域中&#xff0c;支持向量机&#xff08;Support Vector Machine&#xff0c;简称SVM&#xff09;是一种强大的监督学习算法&#xff0c;常用于分类和回归分析。它的优点之一是可以适用于复杂的数据集&#xff0c;并且在高维空间中表现良好。在本文中&am…

【示例】MySQL-MySQL中常见的锁

前言 本文主要讲述MySQL中常见的锁。 总结 | 各类别锁的名字 锁级别锁名字解释全局锁read lock全局锁只有可读锁表级锁 - 表锁read lock 表共享读锁write lock 表独占写锁表级锁 - 元数据锁&#xff08;meta data lock&#xff0c;MDL&#xff09;SHARED_READ_ONLYSHARED_NO…

OSPF实验

需求&#xff1a; 1、R1-R3为区域0&#xff0c;R3到R4为区域1&#xff1b;其中R3的环回也在区域0&#xff0c;P1-R3分别有一个环回接口 2、R1-R3 R3为DR设备&#xff0c;没有BDR 3、R4环回地址已固定&#xff0c;其他所有网段使用192.168.1.0/24进行合理分配 4、R4环回不能…

【golang】动态生成微信小程序二维码实战下:golang 生成 小程序二维码图片 并通过s3协议上传到对象存储桶 | 腾讯云 cos

项目背景 在自研的系统&#xff0c;需要实现类似草料二维码的功能 将我们自己的小程序&#xff0c;通过代码生成相想要的小程序二维码 代码已经上传到 Github 需要的朋友可以自取 https://github.com/ctra-wang/wechat-mini-qrcode 一、生成Qrcode并提交到对象存储 通过源生A…

Kubernetes(k8s):深入理解 Kubernetes 中的污点(Taints)与容忍度(Tolerations)

Kubernetes&#xff08;k8s&#xff09;&#xff1a;深入理解 Kubernetes 中的污点&#xff08;Taints&#xff09;与容忍度&#xff08;Tolerations&#xff09; 1、污点&#xff08;Taints&#xff09;2、容忍度&#xff08;Tolerations&#xff09;3、示例演示-测试污点的具…

自动化测试(selenium篇)

这次我们来介绍selenium 我们主要来讲解这几个要点 1.什么是自动化测试 2.什么是selenium 3.为什么来讲selenium 4.selenium的环境搭建 5.selenium的 API 1.什么是自动化测试 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或者系统&#xff0c;预设条…

蓝宝石衬底材料具有广阔消费市场 行业景气度良好

蓝宝石衬底材料具有广阔消费市场 行业景气度良好 衬底是由半导体单晶材料制造而成的晶圆片&#xff0c;既可以直接进入晶圆制造环节生产半导体器件&#xff0c;也可以进行外延工艺加工生产外延片&#xff0c;是电子元件的主体结构和支撑载体。蓝宝石衬底材料具有良好的透光性、…

burpsuite最新版2024.3.1安装

burpsuite最新版安装 环境 windows jdk22 BurpLoaderKeygen.jar burpsuite profression 2024.3.1 链接 链接&#xff1a;https://pan.baidu.com/s/1N6nggZZezg8y1FHpgwJmeg 提取码&#xff1a;n6uqjdk以及破戒方式这里不做介绍 注意事项 使用BurpLoaderKeygen.jar 破解之后…

Windows 2003 R2与Windows 2022建立域信任报错:本地安全机构无法跟域控制器获得RPC连接。请检查名称是否可以解析,服务器是否可用。

在Windows Server 2003 R2与Windows Server 2022之间建立域信任时遇到“本地安全机构无法与域控制器获得RPC连接”的错误&#xff0c;可能是由于以下几种原因&#xff1a; DNS 解析问题&#xff1a; 确保源域和目标域的DNS配置正确&#xff0c;能够互相解析对方的域名和IP地址。…

多语言婚恋交友APP开发流程一览

近年来&#xff0c;随着全球化的发展和人们对跨文化交流的需求增加&#xff0c;多语言婚恋交友APP的需求逐渐增长。开发这类APP需要考虑到不同语言和文化下用户的需求&#xff0c;涉及到一系列独特的流程和挑战。本文将从专家角度为您解析多语言婚恋交友APP的开发流程&#xff…

【虚幻引擎】DTProjectSettings 蓝图获取基本项目配置插件使用说明 获取项目命名,项目版本,公司名,公司识别名,主页,联系方式

本插件可以使用蓝图获取到项目的一些基本配置&#xff0c;如获取&#xff1a;公司名、公司识别名、版权声明、描述、主页、许可条款、隐私政策、项目ID、项目命名、项目版本、支持联系方式、项目显示标题、项目调试标题信息、应保留窗口宽高比、使用无边框窗口、以VR启动、允许…

【Vue3进阶】- 第2学堂小商城项目后端准备和接口文档

简介 在大多数前端项目开发中&#xff0c;都需要与后端进行接口交互&#xff0c;后端通常会以文档的形式提供接口信息&#xff0c;前端开发者通过阅读这些文档&#xff0c;了解后端接口的功能和使用方法&#xff0c;从而实现数据的获取和提交等功能。 第二学堂小商城教程后端…

03攻防世界-unserialize3

根据题目可以看出&#xff0c;这是个反序列化的题目 打开网址观察题目可以看到这里是php的代码&#xff0c;那么也就是php的反序列化 本题需要利用反序列化字符串来进行解题&#xff0c;根据源码提示我们需要构造code。 序列化的意思是&#xff1a;是将变量转换为可保存或传输…

MongoDB爬虫:(某扑)实战

https://bbs.hupu.com/bxj网页地址: https://bbs.hupu.com/bxj 然后我们在网页上定义帖子名称、帖子链接、创建时间、回复数、最后回复用户...... 除此之外,我们发现虎扑步行街最多显示的页数(20): 、 当我们打开第3页的时候,网页的URL的地址变为了:https://bbs.hupu.…