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

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

在这里插入图片描述

链表面试题

  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双向长短期记忆神经网络故障诊断 专栏介绍 订阅【故障诊断】专栏,不定期更新机器学习和深度学习在故障诊断中的应用;订阅

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

全连接神经网络 全连接神经网络的结构 整体结构 神经网络:类似神经元,前一层可以不断地传递给下一层。 神经网络模型由多个单元结构组成。 单元结构 单元结构的数学公式: 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.编程实现快速排序降序

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;…

使用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; 地表覆盖分布…

瑞士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;实施中小企业数字化赋能专项行动。数字化转型有利于中小企业降低成本、提高效率、加速转型升级…

k8s Sidecar filebeat 收集容器中的trace日志和app日志

目录 一、背景 二、设计 三、具体实现 Filebeat配置 K8S SideCar yaml Logstash配置 一、背景 将容器中服务的trace日志和应用日志收集到KAFKA&#xff0c;需要注意的是 trace 日志和app 日志需要存放在同一个KAFKA两个不同的topic中。分别为APP_TOPIC和TRACE_TOPIC 二、…

Tensorflow2.0笔记 - Tensor的限值clip操作

本笔记主要记录使用maximum/minimum,clip_by_value和clip_by_norm来进行张量值的限值操作。 import tensorflow as tf import numpy as nptf.__version__#maximum/minimumz做上下界的限值 tensor tf.random.shuffle(tf.range(10)) print(tensor)#maximum(x, y, nameNone) #对…

贪吃蛇---C语言---详解

引言 C语言已经学了不短的时间的&#xff0c;这期间已经开始C和Python的学习&#xff0c;想给我的C语言收个尾&#xff0c;想起了小时候见过别人的老人机上的贪吃蛇游戏&#xff0c;自己父母的手机又没有这个游戏&#xff0c;当时成为了我的一大遗憾&#xff0c;这两天发现C语…

【LeetCode】每日一题 2024_1_30 使循环数组所有元素相等的最少秒数(哈希、贪心、扩散)

文章目录 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01;题目&#xff1a;使循环数组所有元素相等的最少秒数题目描述代码与解题思路 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 今天的题目类型差不多是第一次见到&#xff0c;原来题目描述…