题目汇总
1、移除元素
203. 移除链表元素
237. 删除链表中的节点(链表IQ题)
83. 删除排序链表中的重复元素(递归、迭代)
82. 删除排序链表中的重复元素 II(递归+讨论、迭代)
19. 删除链表的倒数第 N 个结点(双指针)
876. 链表的中间结点(快慢指针)
2、设计链表(集中基本操作,建立链表、插入、删除)
707. 设计链表
3、反转链表
206. 反转链表(递归)
92. 反转链表 II
234. 回文链表(部分反转)
25. K 个一组翻转链表(反转区域头插法)
24. 两两交换链表中的节点(快慢指针、迭代)
4、链表相交
面试题 02.07. 链表相交
142. 环形链表 II
5、合并链表
21. 合并两个有序链表
23. 合并K个升序链表
6、综合
143. 重排链表
86. 分隔链表(模拟)
303. 区域和检索 - 数组不可变
1、203. 移除链表元素
1)问题描述
2)思路
(1)通过递归的方法(先进后出),从链表最后一个元素遍历到表头
递归
✨复杂度分析:时间复杂度,空间复杂度。
(2)迭代(实现过程力扣)
迭代
✨时间复杂度为,空间复杂度为。
tips:
(i)如果只是传递地址,则不需要申请动态空间,因为不需要建立结点。
(ii)题目这里的头结点数据域非空,是链表的开始。
同类练习:
83. 删除排序链表中的重复元素
82. 删除排序链表中的重复元素 II
2、707. 设计链表
1)问题描述
2)代码实现(单链表)力扣
(tips:尝试写个双链表、循环链表)
3、206. 反转链表
1)问题描述
2)思路
(1)迭代方法,但是注意用一个结点存储前一个结点的信息,方便后续赋值,而每次存储使用完了记得更新!!!(就是因为没有更新,所以当时在写的时候出现了死循环)
时间复杂度为,其中为链表长度,需要遍历链表一次。
空间复杂度为.
(2)递归
时间复杂度为,其中 n是链表的长度。需要对链表的每个节点进行反转操作。
空间复杂度为,其中 n是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 n 层。
同类练习:
92. 反转链表 II
234. 回文链表
25. K 个一组翻转链表
4、24. 两两交换链表中的节点
1)问题描述
2)思路分析
通过观察我发现如果把整张链表分奇数项和偶数项,实际上是发生了“移位”,于是我想到,用两个指针,一个指向当前结点的p指针,一个是指向当前结点的前驱指针prev,通过改变指向达到目的。
这里有几个细节需要注意:
(1)更改链表的操作的工具:指针 + 虚拟头指针(这需要额外申请空间)固定格式:
(2)需要考虑几个特殊情况:i) 空链表;ii)奇数个元素的链表。
(3)链表头两个结点发生对换之后,头结点发生了改变,这时候要告诉程序“头结点”是谁(对head重新赋值)
(4)程序返回结果是head 还是dummyhead -> next?
3)代码实现
对比题解:
3.1)递归法 力扣
时间复杂度是,其中 n是链表的节点数量。需要对每个节点进行更新指针的操作。
空间复杂度是,其中 n是链表的节点数量。空间复杂度主要取决于递归调用的栈空间。
3.2)迭代法 力扣
时间复杂度为,其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
空间复杂度为
5、19. 删除链表的倒数第 N 个结点
比较常规简单,关键是感受一下栈方法、双指针法
1)栈方法
时间复杂度为,其中是链表的长度。
空间复杂度为,为链表长度,主要为栈的开销。
2)双指针法
时间复杂度为。
空间复杂度为。
⚠️这里面思想很精妙的地方在于:我要找倒数第n个元素,就相当于找顺数的l - n个(l为链表长度)。
利用这个思路,我让first指针走n步。
然后让first和second一起走(second是从头部开始的,first从第n个位置),这时候,当first走到链表尾部的时候,second和first一共走了 l - n步。也就是second定位到了倒数第n个元素。
精妙的地方在于它选用了参考系first来定位。
3)递归方法
6、面试题 02.07. 链表相交
这一题要做出来不难,但这里面有好思路值得学习。
1)问题描述
2)分析
这一道题有好多方法值得借鉴学习。
1)最常规想法:把两个链表先“预处理”到同一起跑线上(起点到终点位置长度一样),然后再遍历比较。力扣,这里有一个技巧,就是规定curA永远指向较长的链表!!!(遗留问题:如何写一个交换函数,能够交换不同数据类型的元素??)
2)建立两个栈分别存储两个链表,根据栈前进后出(FILO)特点,比较。力扣,注意,虽然说栈存储了链表元素,但是,比较的是栈元素的“内部成员”,不是栈元素(结构体)本身。
3)通过观察,两个指针(curA,curB)分别从两个链表出发(headA,headB),当遍历完各自的链表,就跳转到对方的链表(curA = headB,curB = headA),遍历到最后都有curA == curB,只是若有交点,则curA == curB && curB != NULL,如果没有交点,则curA == curB == NULL 。
7、142. 环形链表 II
理解(参考力扣)
同类型:
1)141. 环形链表
8、21. 合并两个有序链表
1)问题描述
2)代码赏析:
(1)精简,几行代码描述多种情况。
9、23. 合并K个升序链表
1)问题描述
2)思路
(1)由上一题,不停调用两两合并的链表。力扣
(2)利用分治方法,链表两两一个组,先进行合并,合并后的链表由再两两一组,进行合并,知道最后合并为一个链表。力扣
复杂度分析
10、876. 链表的中间结点
1)问题描述
2)分析
这道题要实现不难,有一个很棒的技巧——快慢指针法(前面环形链表的技巧),当fast走到最后时,slow一定走到了链表中间了,这时候只要返回slow即可。这里面有一个值得注意的地方,就是用快慢指针的时候,while循环体的判断语句,用(fast != NULL && fast -> next != NULL),否则,若fast -> next == NULL,那么循环体内的fast更新(fast = fast -> next -> next;)会出现报错。