C语言中链表中经典面试题

简介: 移除链表元素反转链表 合并两个有序链表 总结

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

移除链表元素

反转链表

合并两个有序链表

总结


移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

示例 1:

34F392E3-836D-406D-806E-7145559712EC.jpeg

输入:head = [1,2,6,3,4,5,6], val = 6

输出:[1,2,3,4,5]


示例 2:

输入:head = [], val = 1

输出:[]


示例 3:

输入:head = [7,7,7,7], val = 7

输出:[]


提示:

  • 列表中的节点数目在范围 [0, 104]
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

解题思路:

解题的关键在于我们需要大致判断链表的几种情况,然后通过调试,一步一步通过测试用例,这里我们可以分为三种链表,第一种就是链表为空,这种直接返回空指针,第二种就是链表的第一个节点的val值等于测试用例的val,这里我们就需要进行换头处理,就是跳过第一个节点,把第二个节点当作头,第三种val值在链表非头的位置,从头开始寻找,找到等于val的节点,将val的上个节点连接到val的下个节点。因为我们需要知道val的前后两个节点,所以采用双指针的方法

1. struct ListNode* removeElements(struct ListNode* head, int val)
2. {
3. //这就是第一种情况,如果头为空,直接返回空值
4. if(head==NULL)
5.     {
6. return NULL;
7.     }
8. struct ListNode* prev=NULL,*cur=head;//双指针的方法,一前一后的指针
9. while(cur)//通过循环遍历整个链表
10.     {
11. if(cur->val==val)
12.         {
13. if(prev==NULL)
14.             {
15.                 cur=cur->next;
16.                 head=cur;
17.             }
18. else
19.             {
20.                 prev->next=cur->next;
21.                 cur=cur->next;
22.             }
23.         }
24. else
25.         {
26.             prev=cur;
27.             cur=cur->next;
28.         }
29.     }
30. return head;
31. }

反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

FAF7D1B1-87F9-4AD5-99C3-3C82252208B0.jpeg

输入:head = [1,2,3,4,5]

输出:[5,4,3,2,1]


示例 2:

输入:head = [1,2]

输出:[2,1]


示例 3:

输入:head = []

输出:[]


提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

解题思路:

解题的关键在于我们需要大致判断链表的几种情况,然后通过调试,一步一步通过测试用例,这题分为两种情况,第一种链表为空的时候,就直接返回空指针,第二种链表不为空时,我们采用的是在原有的链表上进行改动,就是将原有的节点指向改变,这里需要记录三个节点的位置,所以需要三个指针

1. struct ListNode* reverseList(struct ListNode* head)
2. {
3. if(head==NULL)
4.     {
5. return NULL;
6.     }
7. struct ListNode* n1=NULL;
8. struct ListNode* n2=head;
9. struct ListNode* n3=head->next;
10. while(n2)
11.     {
12.         n2->next=n1;
13.         n1=n2;
14.         n2=n3;
15. if(n3!=NULL)
16.         {
17.             n3=n3->next;
18.         }
19.     }
20. return n1;
21. }

合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:

47DABE23-828D-4CF5-A183-F82EAB2669C5.jpeg

输入:l1 = [1,2,4], l2 = [1,3,4]

输出:[1,1,2,3,4,4]


示例 2:

输入:l1 = [], l2 = []

输出:[]


示例 3:

输入:l1 = [], l2 = [0]

输出:[0]


提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1l2 均按 非递减顺序 排列

解题思路:

解题的关键在于我们需要大致判断链表的几种情况,然后通过调试,一步一步通过测试用例,这个链表分为四种情况,第一种list1为空时,直接返回list2,第二种list2为空时,直接返回list1,第三种list1和list2都为空时,直接返回空指针,第四种list1和list2都不为空时,首先我们的需要一个头指针去保存头节点的位置,我们需要去判断list1和list2的头节点的val值大小情况,谁小就让头指针去指向谁,然后,我们需要遍历两个链表,只要其中一个链表为空,就跳出循环

1. struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
2. {
3. if(list1==NULL)
4.     {
5. return list2;
6.     }
7. if(list2==NULL)
8.     {
9. return list1;
10.     }
11. if(list1==NULL&&list2==NULL)
12.     {
13. return NULL;
14.     }
15. struct ListNode* cur=NULL;
16. struct ListNode* head=NULL;
17. while(list1&&list2)
18.     {
19. if(list1->val<list2->val)
20.         {
21. if(head==NULL)
22.             {
23.                 head=cur=list1;
24.             }
25. else
26.             {
27.                 cur->next=list1;
28.                 cur=list1;
29.             }
30.             list1=list1->next;
31.         }
32. else
33.         {
34. if(head==NULL)
35.             {
36.                 head=cur=list2;
37.             }
38. else
39.             {
40.                 cur->next=list2;
41.                 cur=list2;
42.             }
43.             list2=list2->next;
44.         }
45.     }
46. if(list1==NULL)
47.     {
48.         cur->next=list2;
49.     }
50. if(list2==NULL)
51.     {
52.         cur->next=list1;
53.     }
54. return head;
55. }

总结

做链表的题的确需要一番思索,我在做第一个题的时候,做了大概两天时间,但还是没有完全通过测试用例(可能我比较愚笨),我就放弃了这道题。过了几天我重新去做这道题,通过了一些方法,最终解决了这道题。这些方法我归结了一下,可以适用于大部分链表类的测试题,第一:画图!画图!画图!重要的事情说三遍,我感觉之所以之前没有做出来这道题,是我没有认真画图的原因,认真画图非常关键,为什么强调认真画图,我之前做题的时候,就老是把图画的很乱,而且画图的位置空间也不足,导致有时候一次测试用例都没有走完,我就放弃了,后来做题过程中,我就认认真真画图,然后走完了几个测试用例,我就这样完成了这道题。第二:有时候我们感觉逻辑没有问题,但是还是存在错误,我们就需要进行调试了,因为这些题目是在线OJ题,一般是不能调试的,所以我们需要在自己的编译器上进行调试,进行调试后,我们就能很容易的到出错的位置,这样有助于我们完成这道题。

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸  

相关文章
|
3月前
|
存储 安全 编译器
C语言面试题1-10
指针声明后立即初始化。 内存释放后将指针置为NULL。 避免越界访问。 10. 一个指针变量占几个字节? 一个指针变量的大小与系统和编译器相关。在32位系统中,指针变量占4个字节;在64位系统中,指针变量占8个字节。 通过深入了解以上问题,能够更好地掌握C语言内存管理的核心概念,提高编写高效、安全代码的能力。
40 1
|
3月前
|
存储 缓存 前端开发
【数据结构/C语言】深入理解 双向链表
【数据结构/C语言】深入理解 双向链表
|
11天前
|
存储 C语言
C语言程序设计核心详解 第九章 结构体与链表概要详解
本文档详细介绍了C语言中的结构体与链表。首先,讲解了结构体的定义、初始化及使用方法,并演示了如何通过不同方式定义结构体变量。接着,介绍了指向结构体的指针及其应用,包括结构体变量和结构体数组的指针操作。随后,概述了链表的概念与定义,解释了链表的基本操作如动态分配、插入和删除。最后,简述了共用体类型及其变量定义与引用方法。通过本文档,读者可以全面了解结构体与链表的基础知识及实际应用技巧。
|
11天前
|
存储 算法 C语言
C语言手撕实战代码_循环单链表和循环双链表
本文档详细介绍了用C语言实现循环单链表和循环双链表的相关算法。包括循环单链表的建立、逆转、左移、拆分及合并等操作;以及双链表的建立、遍历、排序和循环双链表的重组。通过具体示例和代码片段,展示了每种算法的实现思路与步骤,帮助读者深入理解并掌握这些数据结构的基本操作方法。
|
17天前
|
存储 测试技术 C语言
C语言实现链表的各种功能
本文详细介绍了如何使用C语言实现链表的各种功能,包括链表节点结构的定义与操作函数的实现。链表作为一种常用的数据结构,具有节点自由插入删除、动态变化等特点。文中通过`link_list.h`和`link_list.c`两个文件,实现了链表的初始化、插入、删除、查找、修改等核心功能,并在`main.c`中进行了功能测试。这些代码不仅展示了链表的基本操作,还提供了丰富的注释帮助理解,适合作为学习链表的入门资料。
|
6天前
|
C语言
C语言里的循环链表
C语言里的循环链表
|
1月前
|
存储 C语言
【数据结构】c语言链表的创建插入、删除、查询、元素翻倍
【数据结构】c语言链表的创建插入、删除、查询、元素翻倍
【数据结构】c语言链表的创建插入、删除、查询、元素翻倍
|
1月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
34 6
|
30天前
|
算法 C语言
【面试题】【C语言】寻找两个正序数组的中位数
【面试题】【C语言】寻找两个正序数组的中位数
10 0
|
2月前
|
存储 数据管理 C语言
C语言实战 | 使用链表完成“贪吃蛇”游戏
【7月更文挑战第1天】整体思维,即系统思维,强调以整体视角理解事物。在编程中,结构体体现这种思想,将相关变量打包处理。示例展示了如何用链表而非数组实现“贪吃蛇”游戏,链表提供了更灵活的动态数据管理。一系列代码图片详细描绘了链表结构体在游戏中的应用,包括节点定义、移动、碰撞检测等,凸显了使用链表的优势和代码的清晰组织。
32 0
C语言实战 | 使用链表完成“贪吃蛇”游戏