【链表OJ】常见面试题

news/2024/10/22 6:01:01/

学习完链表后,当然还需要实操才行。

文章目录

  • 1.[移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/description/)
    • 1.1 题目要求
    • 1.2 迭代法
    • 1.3 递归法
  • 2. [反转链表](https://leetcode.cn/problems/reverse-linked-list/description/)
    • 2.1 题目要求
    • 2.2 迭代法
    • 2.3 递归法
  • 3. [链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/description/)
    • 3.1 题目要求
    • 3.2 快慢指针
  • 4. [合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/description/)
    • 4.1 题目要求
    • 4.2 迭代法
    • 4.3 递归法

1.移除链表元素

移除<a class=链表元素" />

1.1 题目要求

写编程题首先需要了解题目到底问的是什么,要认真的阅读题目,找出题目的要求。不然可能会因为题目看错了,导致后面的代码全部写错就得不偿失了。
移除链表元素这题比较的简单,题目要求一目了然:将链表中值为val的节点全部移除。

1.2 迭代法

采用循环的方式解决问题,解决的方式其实是类似于删除链表pos位置的节点的。为了删除pos位置的节点我们是要知道pos节点前后的节点。这里也一样,遍历链表找到符合要求的节点就将该节点前的节点指向该节点的后一个节点。
迭代法

但是有一种特殊情况就是符合条件的节点是第一个节点,这样的话,prev就无法指向cur的前一个节点。为了解决这一情况,可以先预处理这种情况,当然也可以在循环里加入特别判断。

//预处理目标节点为链表第一个节点的情况
struct ListNode* removeElements(struct ListNode* head, int val) {while(head!=NULL&&head->val == val)head = head->next;struct ListNode* cur = head;struct ListNode* prev = cur;while(cur){struct ListNode* next = cur->next;if(cur->val == val){prev->next = next;free(cur);cur = NULL;}elseprev = cur;cur = next;}return head;
}//在循环中加入特别判断
struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode* prev = NULL;struct ListNode* cur = head;while(cur){if(cur->val == val){struct ListNode* next = cur->next;free(cur);if(prev)prev->next = next;elsehead = next;cur = next;}else{prev = cur;cur = cur->next;}}return head;
}

其实还可以加入一个虚拟的头节点,也可以很好的解决问题。读者可以尝试一下。

1.3 递归法

链表的性质就决定了它是具有递归的性质的,可以看作特殊的二叉树来看。因此链表的题目也常常可以用递归来解决问题。
即使是递归,我们在删除目标节点时也是需要找到目标节点的前一个节点和后一个节点的。后一个节点好办,就是cur->next。可是前一个节点怎么找呢?
答案就在上一个函数里,因为函数会一层层的递归下去,我让上一层的函数中的节点指向下一个函数不就可以吗,这样就找到目标节点前一个节点,然后就是如果当前节点是目标节点就返回目标节点的下一给节点,不是目标节点就返回当前节点。
最后确定一下递归的停止条件,当节点为NULL时肯定就不能在递归下去了,返回当前节点(NULL)就可以了。

struct ListNode* removeElements(struct ListNode* head, int val) {if(head == NULL)return head;head->next = removeElements(head->next,val);return head->val == val ? head->next : head;
}

2. 反转链表

反转<a class=链表" />

2.1 题目要求

链表反转,然后返回头节点。

2.2 迭代法

为了将链表反转,使得1->2->3->4->NULL变为4->3->2->1->NULL
在遍历链表时就要将当前节点的next指向其前一个节点,所以我们肯定需要一个指针来存储前一个节点的地址。prev在初始化时指向NULL。在迭代时,我们只需要将当前节点cur的next指向prev,然后再更新cur和prev就可以了。
最后返回prev,次数prev就是头节点。

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

2.3 递归法

递归法比较难,看不懂可自行跳过。
因为要反转链表,我们要先通过递归找到链表的最后一个节点,也就是新链表的第一个节点。
当我们找到了,就要开始返回
递归法

代码的执行逻辑就和我画的这张图一样

struct ListNode* reverseList(struct ListNode* head) {if (head == NULL || head->next == NULL) {return head;}struct ListNode* newHead = reverseList(head->next);head->next->next = head;head->next = NULL;return newHead;
}

3. 链表的中间结点

<a class=链表的中间节点" />

3.1 题目要求

找到链表的中间节点,如果有两个中间结点,则返回第二个中间结点

3.2 快慢指针

定义两个链表节点的指针变量,初始化时都指向链表的第一个节点。
不同的时,一个指针一次走两个节点的距离,一个走一个节点的距离。如此一来当快指针指向最后一个节点时,慢指针不就走到了中间吗。
不过还是要注意是快指针是不能走到最后一个节点的,如果快指针走到了最后一个节点,fast->next是NULL,没有next了,所以我们的判断条件还要加上fast->next不能为NULL

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

4. 合并两个有序链表

合并两个有序<a class=链表" />

4.1 题目要求

让两条升序的链表合成一个非降序的链表

4.2 迭代法

我们可以设置一个哨兵位,这样可以使题目简单些。
让两条升序的链表合成一个非降序的链表,我们设置两个指针,分别指向不同的链表,进入循环开始比较,如果cur1的值小于cur2的值,那么我们就把cur1节点接到新的链表当中,为了每次接到新的链表的最后,我们还需要设置一个tial指针指向新链表的末尾,以后的每次操作我们都让比较中更小的接到新链表后,在让值小的那个节点往后移动。
但是最后还是会存在一条链表没有遍历完,最后判断一下那条没有完,直接让那条链表接到新链表的后面。
最后的最后返回是不能返回哨兵位的,我们返回哨兵位的下一个节点。
迭代法

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {struct ListNode* cur1 = list1;struct ListNode* cur2 = list2;struct ListNode* phead = (struct ListNode*)malloc(sizeof(struct ListNode));phead->val = -1;phead->next = NULL;struct ListNode* tail = phead;while(cur1&&cur2){if(cur1->val>cur2->val){tail->next = cur2;cur2 = cur2->next;}else{tail->next = cur1;cur1 = cur1->next;}tail = tail->next;}tail->next = (cur1==NULL)?cur2:cur1;return phead->next;
}

4.3 递归法

主要的逻辑是和迭代一样的,但是递归会更难理解一些。
如果list1或者list2一开始就是空链表 ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断list1和 list2 哪一个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点。如果两个链表有一个为空,递归结束。

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if(list1==NULL)return list2;else if(list2 == NULL)return list1;else if(list1->val<=list2->val){list1->next = mergeTwoLists(list1->next,list2);return list1;}else{list2->next = mergeTwoLists(list1,list2->next);return list2;}
}

http://www.ppmy.cn/news/1505064.html

相关文章

《LeetCode热题100》---<5.①普通数组篇五道>

本篇博客讲解LeetCode热题100道普通数组篇中的五道题 第一道&#xff1a;最大子数组和&#xff08;中等&#xff09; 第二道&#xff1a;合并区间&#xff08;中等&#xff09; 第一道&#xff1a;最大子数组和&#xff08;中等&#xff09; 法一&#xff1a;贪心算法 class So…

共享`pexlinux`数据文件的网络服务

实验环境准备&#xff1a; 1.红帽7主机 2.要全图形安装 3.配置网络为手动&#xff0c;配置网络可用 4.关闭vmware DHCP功能 一、kickstart自动安装脚本制作 1.安装图形化生成kickstart自动脚本安装工具 2.启动图形制作工具 3.图形配置脚本 这里使用的共享方式是http&#xff0…

酒店管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;酒店管理员管理&#xff0c;房间类型管理&#xff0c;房间信息管理&#xff0c;订单信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;房间信息…

微应用(Micro-Applications)、微前端(Micro Frontend)、Qiankun 框架之间的区别和联系

简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo :联系我们:VX :tja6288 / EMAIL: 347969164@qq.com 文章目录 微应用(Micro-Applications)、微…

Go语言加Vue3零基础入门全栈班11 Go语言+gorm用户管理系统实战 2024年08月03日 课程笔记

概述 如果您没有Golang的基础&#xff0c;应该学习如下前置课程。 Golang零基础入门Golang面向对象编程Go Web 基础Go语言开发REST API接口_20240728Go语言操作MySQL开发用户管理系统API教程_20240729Redis零基础快速入门_20231227GoRedis开发用户管理系统API实战_20240730Mo…

JS如何实现禁止截屏、打印、另存为操作?

禁止缓存可以前台HTML使用 <meta http-equiv="pragma" content="no-cache" /> 屏蔽选中、粘贴、复制、剪切、右键菜单、禁止新窗口打开 HTML <body οncοntextmenu="return false" onselectstart="return false" οncοn…

搭建 Rancher 服务,配置k8s集群

1. 前提条件 前提条件&#xff1a; 安装docker&#xff0c;要求版本各节点版本一致。网上还有额外的要求&#xff1a;关闭swap、禁用selinux等等。 2. 搭建 Rancher 服务 直接通过docker命令实现即可&#xff0c;很方便。 docker run -d \--name rancher \--restart unles…

go的并发任务如何优雅的实现错误终止

errgroup使用案例 在Go语言中&#xff0c;并发任务通常通过goroutine来实现&#xff0c;而错误处理和任务终止的优雅性则依赖于适当的同步机制和错误传播策略。 场景: 管理一个任务的一组子任务&#xff0c;每个子任务一个协程每个子任务必须保证都成功&#xff0c;一个出现…