当前位置: 首页 > news >正文

【Leetcodenowcode数据结构】单链表的应用(进阶)

系列文章目录

《Leetcode&nowcode代码强化刷题》


文章目录

  • 系列文章目录
  • 前言
  • 正文
    • 一.链表分割
      • 代码块1
      • 代码块2
      • 代码块3
      • 代码块4
    • 二.随机链表的复制
      • 代码块1(拷贝)
      • 代码块2(插入)
      • 代码块3
      • 代码块4
      • 代码块5
  • 总结


前言

数据结构与算法是计算机领域的核心,既是面试考察重点,也是优化项目性能的关键。而刷题是掌握它最有效的方式,能帮我们巩固理论、提升解题能力。​
我选择LeetCodeNowCode 作为主要刷题平台:LeetCode 题目丰富、分类清晰,适合夯实基础;NowCode 贴近国内企业笔试场景,助力对接实战需求,二者互补性强。​
这份刷题记录不只是题目与答案的罗列,更会记录解题思路、难点易错点,以及解法优化过程。希望它能成为我的复盘工具,也为其他学习者提供参考。​
接下来,就从第一道题开始,在刷题中积累提升,让数据结构与算法成为解决问题的有力工具。


正文

一.链表分割

题目链接:链表分割:
题目描述
在这里插入图片描述

题目分析
题目很短,大致的意思就是:给我们一个链表,让我们在不改变数据顺序的前提下,将链表中值小于x的结点放在前面其他放在后面
这里的不改变顺序,指的是相对顺序,例如下面这个链表
在这里插入图片描述
如果我们x=3,这时候按照题目要求,不改变相对顺序,划分链表
对于小于3的1和2结点,我们要排在前面,并且顺序还是1在前,2在后;
对于不小于3的结点,我们都排在后面,顺序是6,3,5,最后排成这样:
在这里插入图片描述

思路讲解
我们首先可能会想到遍历链表,把每一个比x大的数据都进行尾插再删除
这个方法是可以的,但是考虑到这个方法时间复杂度有点大,我们可以再想想其他的

既然是划分链表,我们可以先创建两个新链表,一个用存小于x的结点,另一个用来存不小于x的结点,最后再把两个链表拼接起来
在这里插入图片描述

我们先创建这两个链表,考虑到空链表情况,我们需要创建哨兵位

代码块1

 //创建大小链表//小链表ListNode* lessHead = NULL, *lessTail = NULL;lessHead = lessTail = (LTN*)malloc(sizeof(LTN));//大链表ListNode* greaterHead = NULL, *greaterTail = NULL;greaterHead = greaterTail = (LTN*)malloc(sizeof(LTN));

之后我们需要遍历原链表,按照划分要求把每个结点分别插入到不同的链表

代码块2

  LTN* pcur = pHead;
//遍历原链表,按照大小插入不同链表while (pcur != NULL) {if (pcur->val < x) { //插入小链表lessTail->next = pcur;lessTail = lessTail->next;} else { //插入大链表greaterTail->next = pcur;greaterTail = greaterTail->next;}//向后遍历pcur = pcur->next;}

最后拼接两个链表

代码块3

//拼接大小链表lessTail->next = greaterHead->next;

这时候我们提交代码,会出现这样的报错
在这里插入图片描述
原来是我们拼接后半段的大链表,最后一个节点不一定指向NULL
于是我们还需要手动置空

代码块4

//把大链表最后一个结点的next置空greaterTail->next = NULL;

这样这道题目就差不多了

代码展示

/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {public:typedef struct ListNode LTN;ListNode* partition(ListNode* pHead, int x) {//创建大小链表//小链表ListNode* lessHead = NULL, *lessTail = NULL;lessHead = lessTail = (LTN*)malloc(sizeof(LTN));//大链表ListNode* greaterHead = NULL, *greaterTail = NULL;greaterHead = greaterTail = (LTN*)malloc(sizeof(LTN));LTN* pcur = pHead;
//遍历原链表,按照大小插入不同链表while (pcur != NULL) {if (pcur->val < x) { //插入小链表lessTail->next = pcur;lessTail = lessTail->next;} else { //插入大链表greaterTail->next = pcur;greaterTail = greaterTail->next;}//向后遍历pcur = pcur->next;}
//把大链表最后一个结点的next置空greaterTail->next = NULL;
//拼接大小链表lessTail->next = greaterHead->next;//保存新链表的第一个结点LTN* ret = lessHead->next;
//释放空间free(lessHead);free(greaterHead);
//返回新链表return ret;}
};

博主题解

二.随机链表的复制

题目链接:138.随机链表的复制
题目描述
在这里插入图片描述
题目分析
这道题目,让我们去构造链表的深拷贝
什么是深拷贝呢?
假设我们现在要对a=3,继续拷贝,这时候说b也等于3,但是a和b公用3这块内存,这是浅拷贝
深拷贝就是,我们额外在开辟一块新空间,里面放拷贝的数据
在这里插入图片描述
也就是说,这道题目让我们去把原链表的每个节点都去深拷贝一份,再对拷贝出来结点,按照原链表的指向去连接

思路讲解
这里深拷贝我们可以用malloc,next指针也可以按顺序去指,但是random这个指针是无序的,这给我们额外创建链表,再去连接这个做法造成了困难

那么有没有什么方法可以在原有链表的基础上去完成呢?

我们可以先对每个结点进行复制,然后把每个复制结点,插入原结点的后面,如下图
在这里插入图片描述
这时候我们让两个指针,copycur去分别遍历复制结点和原来结点
当我们原链表的random指向NULL的时候,我们让对应的复制结点random也指向NULL;当我们原链表的random不指向NULL的时候,就会发现:

copy->random=cur->random->next

恰好就可以让复制结点的random指针,按照原链表的顺序指好

所以我们先把所有结点拷贝插入链表中

代码块1(拷贝)

// 复制结点Node* newNode = (Node*)malloc(sizeof(Node));newNode->val = x;newNode->next = newNode->random = NULL;return newNode;

代码块2(插入)

Node* pcur = head;while (pcur != NULL) {// 记录下一个结点位置Node* next = pcur->next;Node* copyNode = buyNode(pcur->val);// 复制结点指向nextcopyNode->next = next;// pcur指向复制结点pcur->next = copyNode;// pcur继续遍历pcur = next;}

然后设置复制节点的random指针

代码块3

 Node* pcur = head; // 遍历原结点while (pcur != NULL) {Node* copy = pcur->next; // 遍历复制结点// 标记下一个结点Node* next = copy->next;// 原来的random指向空,复制结点random还是指向空if (pcur->random == NULL) {copy->random = NULL;}// 原来结点的random不指向NULL// copy->random等于cur->random->nextelse {copy->random = pcur->random->next;}pcur = next;}

最后我们让复制的结点单独连接

代码块4

// 断开与原结点的连接Node* pcur = head;Node *copyHead, *copyTail;copyHead = copyTail = pcur->next;while (copyTail->next!=NULL) {pcur = copyTail->next;copyTail->next = pcur->next;copyTail = copyTail->next;}

我们每个循环,我们都需要仔细去想它的循环条件是什么

提交之后,会报错
在这里插入图片描述
样例是空链表,所以我们需要特判

代码块5

// 特判空链表if (head == NULL)return head;

这样我们这道题目就可以解决了
代码展示

/*** Definition for a Node.* struct Node {*     int val;*     struct Node *next;*     struct Node *random;* };*/
typedef struct Node Node;// 复制结点
Node* buyNode(int x) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->val = x;newNode->next=newNode->random=NULL;return newNode;
}void AddNode(Node* head) {Node* pcur = head;while (pcur != NULL) {// 记录下一个结点位置Node* next = pcur->next;Node* copyNode = buyNode(pcur->val);// 复制结点指向nextcopyNode->next = next;// pcur指向复制结点pcur->next = copyNode;// pcur继续遍历pcur = next;}
}
void setRandom(Node* head) {Node* cur = head;        // 遍历原结点while (cur != NULL) {Node* copy = cur->next; // 遍历复制结点// 标记下一个结点Node* next = copy->next;// 原来的random指向空,复制结点random还是指向空if (cur->random == NULL) {copy->random = NULL;}// 原来结点的random不指向NULL// copy->random等于cur->random->nextelse {copy->random = cur->random->next;}cur = next;}
}struct Node* copyRandomList(struct Node* head) {// 特判空链表if (head == NULL)return head;// 添加结点AddNode(head);// 设置复制结点的random指针setRandom(head);// 断开与原结点的连接Node* copy = head->next;Node* cur = copy->next;while (cur != NULL) {copy->next = cur->next;copy = copy->next;cur = copy->next;}return head->next;
}

博主题解


总结

进阶题目,代码量思考量相比较初阶更多一些(尤其第二道),我们需要多去练习掌握,也许第一遍不会去做(第二题第一次真的可以想到这个解法吗ovo),但是我们要不断地去反复总结
下一篇我会为大家带来顺序表相关的题目,希望大家可以多多支持,有什么问题可以评论留言或者后台私信,感谢大家

有佬佬问,题目可以讲的详细一点吗,于是博主加上了思路分析,以后题目如果不是特别简单,博主都会写上思路分析滴,希望对大家有所帮助

http://www.dtcms.com/a/490320.html

相关文章:

  • Python基础语法全解析
  • Spring Boot 3零基础教程,Spring Boot 自定义日志系统,笔记23
  • 智慧园区的安全守护者
  • 【avalonia教程】12自定义Converter
  • 大数据处理:Dask DataFrame,内存不足解决方案?
  • 我的AI助手矩阵:从单模型调用到多模型协作的智能升级
  • 网页制作邢台网站公司wordpress采 文章权限
  • 网站设计方案和技巧新鸿儒网站建设
  • Lua 中的 __index、__newindex、rawget 与 rawset 介绍
  • CAN、ROS数据录制与rqt图形化显示
  • 基于深度学习的卫星图像分类(Kaggle比赛实战)
  • 银河麒麟 aarch64 linux 里面的 qt 发布应用怎么打包
  • linux常用命令(6)——网络管理
  • 江阴建设局网站招考设计说明500字通用
  • Lab Deploying Multi-container Applications
  • 目标检测2
  • 12-用户管理
  • 合肥哪里做网站西安网站建设制作专业公司
  • 中冶东北建设网站装修网站运营
  • Nginx+Lua动态加载黑名单
  • 吕口*了多乐*-(话题)程序系统架构方案
  • Java Spring 框架的`@Autowired` 注解 以及依赖注入分析
  • [Docker集群] Docker 数据持久化
  • MCP vs. API:AI智能体如何更轻松地连接外部世界?
  • 【XR硬件系列】破局“芯”瓶颈:深入浅出解析XR专用芯片的必然性
  • 浙江省建设培训中心的网站小程序开发公司简介
  • Redis 限流解决方案:结合 Lua 脚本、AOP 和自定义注解的实现
  • 游戏画面卡顿残影?这款电竞显示器610Hz + 4K OLED
  • COLMAP原理讲解与使用教程
  • 定位守护童年,科技构筑安全屏障