【数据结构】链表的一些面试题

简单不先于复杂,而是在复杂之后。

在这里插入图片描述

链表面试题

  1. 删除链表中等于给定值 val 的所有结点。OJ链接
//1.常规方法struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode* cur = head, *prev = NULL;while(cur){if(cur->val == val){//1.头删//2.非头删if(cur == head){head = head->next;free(cur);cur = head;}else{prev-> next = cur->next;free(cur);cur = prev-> next;}}else{prev = cur;cur = cur->next;}} return head;
}
//2.新思路
//创建一个新链表,把非val的结点尾插到新链表
struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode* newhead =NULL, *cur = head, *tail = NULL;while(cur){if(cur->val != val){if(tail == NULL){newhead = tail = cur;}else{tail->next = cur;tail = tail->next;}cur = cur->next;}else{struct ListNode* del = cur;cur = cur->next;free(del);}}//最后的节点是val就会出现此问题if(tail){tail->next = NULL;}return newhead;
}

小技巧:在涉及到链表的题的时候调试不太方便,我们需要快速构建一个链表。

int main()
{struct ListNode* n1 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n1);struct ListNode* n2 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n2);struct ListNode* n3 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n3);struct ListNode* n4 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n4);struct ListNode* n5 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n5);struct ListNode* n6 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n6);struct ListNode* n7 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n7);n1->next = n2;n2->next = n3;n3->next = n4;n4->next = n5;n5->next = n6;n6->next = n7;n7->next = NULL;n1->val = 1;n2->val = 2;n3->val = 6;n4->val = 3;n5->val = 4;n6->val = 5;n7->val = 6;return 0;
}

带哨兵位的链表:

  • 哨兵节点(Sentinel Node): 这是一个特殊的节点,它不包含实际数据,仅用于简化代码逻辑。哨兵节点通常作为链表的头部存在,这意味着链表中始终有一个节点,即使链表为空。哨兵节点的存在简化了对链表头部的特殊处理,因为无论链表是否为空,我们都可以始终通过哨兵节点来引导链表的访问。
  • 优点: 哨兵节点可以简化代码实现,避免在对头部进行操作时需要额外的条件检查。

不带哨兵位的链表:

  • 特殊处理头部: 在不使用哨兵节点的情况下,需要特殊处理链表头部,因为在空链表或者插入第一个节点时,需要进行额外的条件检查,以确保正确处理链表头部。
  • 优点: 节省了一个节点的空间开销,因为没有用于哨兵的额外节点。

带哨兵位和不带哨兵位的区别:

在这里插入图片描述

//利用带哨兵位的头节点的链表可以免去判空的步骤struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode* cur = head;struct ListNode* guard = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* tail = guard;while(cur){if(cur->val != val){tail->next = cur;tail = tail->next;cur = cur->next;}else{struct ListNode* del = cur;cur = cur->next;free(del);}}//最后的节点是val就会出现此问题if(tail){tail->next = NULL;}head = guard->next;free(guard);return head;
}

替代之前实现单链表时候传参用的二级指针有两种方式:

  • 返回新的链表头指针
  • 设计为带哨兵位的链表

(单链表在实际应用中很少带头,OJ题链表基本不带头)

  1. 反转一个单链表。OJ链接

在这里插入图片描述

struct ListNode* reverseList(struct ListNode* head) {struct ListNode* cur = head;struct ListNode* newhead = NULL;while(cur){struct ListNode* next = cur->next;cur->next = newhead;newhead = cur;cur = next;}return newhead;
}
//思路2:将链表的指针指向反转
struct ListNode* reverseList(struct ListNode* head) {struct ListNode* prev = NULL;struct ListNode* cur = head;while(cur){struct ListNode* next = cur->next;cur->next = prev;//迭代器prev = cur;cur = next;}return prev;
}
  1. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。OJ链接

在这里插入图片描述

struct ListNode* middleNode(struct ListNode* head) {struct ListNode* fast,*slow;fast = slow = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;
}
  1. 输入一个链表,输出该链表中倒数第k个结点。OJ链接

在这里插入图片描述

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {// write code herestruct ListNode* slow, *fast;slow = fast = pListHead;while(k--){//判断k大于链表长度if(!fast){return NULL;}fast = fast->next;}while(fast){slow = slow->next;fast = fast->next;}return slow;
}
  1. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。OJ链接
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{struct ListNode* guard = (struct ListNode*)malloc(sizeof(struct ListNode));guard->next = NULL;struct ListNode* tail = guard;struct ListNode* cur1 = list1, *cur2 = list2;while(cur1 && cur2){if(cur1->val < cur2->val){tail->next = cur1;cur1 = cur1->next;}else{tail->next = cur2;cur2 = cur2->next;}tail = tail->next;}if(cur1)tail->next = cur1;if(cur2)tail->next = cur2;struct ListNode* head = guard->next;free(guard);return head;
}
  1. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大小或等于x的结点之前。OJ链接

在这里插入图片描述

在这里插入图片描述

class Partition {public:ListNode* partition(ListNode* pHead, int x) {// write code herestruct ListNode* lessTail,*lessGuard,*greaterTail,*greaterGuard;lessTail = lessGuard = (struct ListNode*)malloc(sizeof(struct ListNode));greaterTail = greaterGuard = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* cur = pHead;greaterGuard->next = NULL;lessGuard->next = NULL;while(cur){if(cur->val < x){lessTail->next = cur;lessTail = lessTail->next;}else {greaterTail->next = cur;greaterTail = greaterTail->next;}cur = cur->next;}lessTail->next = greaterGuard->next;greaterTail->next = NULL;pHead = lessGuard->next;free(greaterGuard);free(lessGuard);return pHead;}
};
  1. 链表的回文结构。OJ链表

在这里插入图片描述

class PalindromeList {public:struct ListNode* middleNode(struct ListNode* head) {struct ListNode* fast, *slow;fast = slow = head;while (fast && fast->next) {slow = slow->next;fast = fast->next->next;}return slow;}struct ListNode* reverseList(struct ListNode* head) {struct ListNode* prev = NULL;struct ListNode* cur = head;while (cur) {struct ListNode* next = cur->next;cur->next = prev;//迭代器prev = cur;cur = next;}return prev;}bool chkPalindrome(ListNode* head) {// write code herestruct ListNode* mid = middleNode(head);struct ListNode* rmid = reverseList(mid);while(head && rmid){if(head->val != rmid->val)return false;head = head->next;rmid = rmid->next;}return true;}
};
  1. 输入两个链表,找出它们的第一个公共结点。OJ链表

在这里插入图片描述

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode* curA = headA, *curB = headB;if(headA == NULL || headB == NULL){return NULL;}int lenA = 1;while(curA->next){curA = curA->next;lenA++;}int lenB = 1;while(curB->next){curB = curB->next;lenB++;}if(curA != curB){return NULL;}struct ListNode* longList = headA,*shortList = headB;if(lenA < lenB){longList = headB;shortList = headA;}int gap = abs(lenA - lenB);while(gap--){longList = longList->next;}while(longList != shortList){longList = longList->next;shortList = shortList->next;}return longList;
}
  1. 给定一个链表,判断链表中是否有环。OJ链表

在这里插入图片描述

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

【思路】

快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。

【扩展问题】

  • 为什么快指针每次走两步,慢指针走一步可以?

假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。

此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

  • 快指针一次走3步,走4步,…n步行吗?

    • 快指针一次走 3 步:

      假设slow进环后,fast和slow之间差距N,追赶距离就是N,每追赶一次,之间的距离缩小2步

      如果N是偶数,距离一定会减少到0,也就是两个指针相遇;

      如果N是奇数,距离会减少到1,fast会越过slow指针,fast和slow之间得距离变成了-1,也就是C-1,(C-1是环长度),如果C-1是偶数,再追一圈就可以追上,如果C-1是奇数,永远追不上;

  1. 给定一个链表,返回链表开始入环的第一个结点。如果链表无环,则返回 NULL。OJ链接

在这里插入图片描述

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* slow = head, *fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;if(slow == fast){struct ListNode* meet = slow;while(meet != head){meet = meet->next;head = head->next;}return meet;}}return NULL;
}

在这里插入图片描述

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode* curA = headA, *curB = headB;int lenA = 1;while(curA->next){curA = curA->next;lenA++;}int lenB = 1;while(curB->next){curB = curB->next;lenB++;}if(curA != curB){return NULL;}struct ListNode* longList = headA, *shortList = headB;if(lenA < lenB){longList = headB;shortList = headA;}int gap = abs(lenA - lenB);while(gap--){longList = longList->next;}while(longList != shortList){longList = longList->next;shortList = shortList->next;}return longList;
}struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* slow, *fast;slow = fast = head;while(fast && fast->next){slow = slow->next;          fast = fast->next->next;if(slow == fast){struct ListNode* meet = slow;struct ListNode* next = meet->next;meet->next = NULL;struct ListNode* entry =  getIntersectionNode(head,next);meet->next = next;return entry;}}return NULL;}

在这里插入图片描述

  1. 给定一个链表,每个结点包含一个额外增加的随机指针,该指针可以指向链表中的任何结点或空结点。

​ 要求返回这个链表的深度拷贝。OJ链接

struct Node* copyRandomList(struct Node* head) {// 1.插入copy节点struct Node* cur = head;struct Node* copy;struct Node* next;while(cur){// 复制链接next = cur->next;copy = (struct Node*)malloc(sizeof(struct Node));copy->val = cur->val;cur->next = copy;copy->next = next;// 迭代往后走cur = next;}//2. 更新copy->randomcur = head;while(cur){copy = cur->next;if(cur->random == NULL)copy->random = NULL;elsecopy->random = cur->random->next;//迭代cur = copy->next;} //3. copy节点要解下来链接在一起,然后恢复原链表struct Node* copyHead = NULL, *copyTail = NULL;cur = head;while(cur){copy = cur->next;next = copy->next;//取节点尾插if(copyTail == NULL){copyHead = copyTail = copy;}else{copyTail->next = copy;copyTail = copyTail->next;}//恢复原链表链接cur->next = next;//迭代cur = next;}return copyHead;
}
  1. 其他。ps:链表的题当前因为难度及知识面等等原因还不适合当前学习,下面有OJ链接。

Leetcode OJ链接 + 牛客 OJ链接

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

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

相关文章

Python使用分治算法作归并排序

对于分治算法的一个较为常规的应用中&#xff0c;归并排序是一个使用分治算法的排序方式。给定一个随机排序的数组&#xff0c;我们要将其元素按照升序或者降序的方式进行排序&#xff0c;可以设想到这样的一种算法&#xff0c;如果一个数组的上半部分和下半部分已经排好序&…

聚观早报 | 360 AI搜索App上线;岚图汽车与京东达成合作

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 1月30日消息 360 AI搜索App上线 岚图汽车与京东达成合作 三星电子在硅谷新设实验室 小米平板7系列参数曝光 Spa…

【全csdn最前沿LVGL9】基础对象lv_obj

文章目录 前言一、LVGL9的下载二、基础对象lv_obj2.1 概述2.2 布局2.3 lv_obj的使用创建一个lv_obj设置大小设置位置设置对齐父对象与子对象事件 总结 前言 LVGL&#xff08;LittlevGL&#xff09;是一个开源的嵌入式图形库&#xff0c;用于在嵌入式系统中创建用户界面。LVGL提…

故障诊断 | 一文解决,BiLSTM双向长短期记忆神经网络故障诊断(Matlab)

文章目录 效果一览文章概述专栏介绍模型描述源码设计参考资料效果一览 文章概述 故障诊断模型 | Maltab实现BiLSTM双向长短期记忆神经网络故障诊断 专栏介绍 订阅【故障诊断】专栏,不定期更新机器学习和深度学习在故障诊断中的应用;订阅

qt-C++笔记之contains()和isEmpty()函数、以及部分其他函数列举

qt-C笔记之contains()和isEmpty()函数、以及部分其他函数列举 code review! 文章目录 qt-C笔记之contains()和isEmpty()函数、以及部分其他函数列举contains()isEmpty() 类似的其他函数列举通用容器类函数字符串特有函数 在Qt C开发中&#xff0c; contains() 和 isEmpty()…

【深度学习】全连接神经网络

全连接神经网络 全连接神经网络的结构 整体结构 神经网络:类似神经元,前一层可以不断地传递给下一层。 神经网络模型由多个单元结构组成。 单元结构 单元结构的数学公式: a = h ( w x + b ) a=h(wx+b) a=h(wx+b) h(x):激活函数 比如sigmoid就是激活函数之一隐藏层大多…

Sketch 99.5中文 优秀的网站和移动应用设计软件

Sketch for mac用于数字世界的图形设计。在一个屡获殊荣的软件包中提供强大的工具和优雅的界面。因为做美丽的事情应该是一种快乐&#xff0c;而不是负担。 软件下载&#xff1a;Sketch 99.5中文激活版下载 Sketch支持每层多个填充&#xff0c;边框和阴影&#xff1b;具有强大的…

数据结构day7

1.思维导图 1.二叉树递归创建 2.二叉树先中后序遍历 3.二叉树计算节点 4.二叉树计算深度。 5.编程实现快速排序降序

点云数据集标注的相关工具

点云数据标注是三维计算机视觉领域中重要的一环&#xff0c;专门用于为点云数据添加语义信息&#xff0c;以便进行后续的机器学习和深度学习处理。以下是一些用于点云数据标注的软件及其特点的详细介绍&#xff1a; 1. CloudCompare 描述&#xff1a;CloudCompare是一个开源软…

python中的josn方法相关介绍

如果需要在不同的编程语言之间传递对象&#xff0c;就必须把对象序列化为标准格式&#xff0c;比如XML&#xff0c;但更好的方法是序列化为JSON&#xff0c;因为JSON表示出来就是一个字符串&#xff0c;可以被所有语言读取&#xff0c;也可以方便地存储到磁盘或者通过网络传输。…

太美医疗冲刺港交所上市:融资“数据打架”,老虎基金提前退出

1月29日&#xff0c;浙江太美医疗科技股份有限公司&#xff08;下称“太美医疗”或“太美医疗科技”&#xff09;递交招股书&#xff0c;准备在港交所主板上市。特别说明的是&#xff0c;该公司曾于2021年12月29日在上海证券交易所科创板递交上市申请。 据贝多财经了解&#x…

2024前端面试总结—JS篇(文档持续更新中。。。)

1、Event Loop&#xff08;事件循环&#xff09;机制 JS是单线程的非阻塞语言 为什么是单线程&#xff08;如果js是多线程&#xff0c;那么两个线程同时对同一个Dom进行操作&#xff0c;一个增一个删&#xff0c;浏览器该如何执行&#xff1f;&#xff09; 非阻塞&#xff08;…

2024/1/30 备战蓝桥杯 3-1 栈

目录 小鱼的数字游戏 P1427 小鱼的数字游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 表达式括号匹配 P1739 表达式括号匹配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 【模板】栈 B3614 【模板】栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 小鱼的数字…

使用Neo4j做技术血缘管理

目录 一、neo4j介绍 二、windows安装启动neo4j 2.1下载neo4j 2.2 解压文件 2.3 启动neo4j 三、neo4j基础操作 3.1 创建结点和关系 3.2 查询 3.3 更改 3.4 删除 四、技术血缘Demo实现 4.1 构建节点对象 4.2 构建存储对象 4.3 创建有属性关联关系 4.4 最后是图结果…

中科星图——2020年全球30米地表覆盖精细分类产品V1.0(29个地表覆盖类型)

数据名称&#xff1a; 2020年全球30米地表覆盖精细分类产品V1.0 GLC_FCS30 长时序 地表覆盖 动态监测 全球 数据来源&#xff1a; 中国科学院空天信息创新研究院 时空范围&#xff1a; 2015-2020年 空间范围&#xff1a; 全球 数据简介&#xff1a; 地表覆盖分布…

【四】【C++】日期类简单实现

编写GetMonthDay函数 int GetMonthDay(int year, int month) {static int monthDays[13] {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};if (month 2 && ( (year % 4 0 && year % 100 ! 0) || year % 400 0)) {return 29;}return monthDays[month]…

瑞士0.5米高程地形瓦片数据介绍

一、背景 瑞士是位于中欧的一个国家&#xff0c;以其美丽的自然风光、高质量的生活和强大的金融体系而闻名&#xff0c;其位于欧洲中部&#xff0c;四面环山&#xff0c;与德国、法国、意大利、奥地利和列支敦士登等国家接壤。瑞士境内有许多湖泊和阿尔卑斯山脉的一部分。瑞士…

在 Linux 中挂载新硬盘动态使用

目录 一&#xff1a;添加硬盘并且格式化 二&#xff1a;创建逻辑卷 三&#xff1a;挂载卷到目录 在 Linux 中挂载新硬盘并进行格式化的操作可以按照以下步骤进行&#xff1a; 一&#xff1a;添加硬盘并且格式化 查看现有分区状态和服务器安装的硬盘状态&#xff1a; df -…

node版本切换(nvm)

1.https://github.com/coreybutler/nvm-windows/releases 进入下载nvm管理器 点击下载如果访问不到&#xff0c;可以使用我已下载好上传的 2.将下载文件解压到nvm目录中 3.配置nvm的环境变量 在系统变量中添加&#xff1a; NVM_HOME &#xff1a;包管理器的文件目录 NVM_SYML…

Workfine:用「订阅制」破解中小企业数字化转型困局

中小企业是国民经济和社会发展的重要力量&#xff0c;是扩大就业的载体&#xff0c;是改善民生的关键。《“十四五”数字经济发展规划》明确提出大力推进数字产业化转型&#xff0c;实施中小企业数字化赋能专项行动。数字化转型有利于中小企业降低成本、提高效率、加速转型升级…