刷题有术--“链表” 必备技巧

555 阅读3分钟

在面试中,链表经常作为简单题出现,虽然题目不难,但是面试者常常会因疏忽实现细节,造成无法短时间内bug-free。

今天小编总结链表常用知识点。点赞收藏,关注公众号【眼罩的程序员笔记】,面试前看一遍,快速通关链表题型。

图片

基础操作

01. 快慢指针找中间节点

无论当链表中有奇数还是偶数个节点,slow fast 两指针一开始都指向head。慢指针一次走一步,快指针一次走两步。 直至fast 为NULL或者fast->next为NULL时,此时slow 指向中间节点。

循环结束后指针状态见下图。

图片

02. 原地翻转

不断向后移动相邻的两个指针,翻转两指针间的相邻关系,需注意在翻转之前保存后一个指针的next节点。并且最后把原head的next置为NULL。

如下图红色代表循环第一步,蓝色代表循环第二步。

图片

03. 合并链表

给定两个链表,要求依次选取其中一个节点,合并两个链表。

下图是一个通用的合并思路,这个思路不仅适用于依次选取节点合并,还适用于将两个有序链表合并为一个有序链表。

首先建立一个dummy 头节点作为合并后链表的dummy头结点,用一个尾指针指向合并后链表的最后一个节点。每次循环将tail 连接到headA,headA 连接到 headB,之后tail 更新为headB。

下图中红线代表循环第一轮,蓝线代表循环第二轮。

图片

链表排序

题目:给定链表的头结点 head ,请将其按升序排列并返回 排序后的链表 。

链表的特点造成无法方便的交换任意两个任意位置的节点,所以无法使用快排类的排序算法。

而归并排序非常适合链表排序。递归从底到上,相当将长度为1 的子链表排序之后两个合并成长度2的链表;依次递推。

图片

实现过程就用到了上述基础操作中的「快慢指针找中间节点」来把链表一分为二;用「合并链表」将排序好的子链表合并成一个有序的长链表。

链表有环

1. 给你一个链表的头节点 head ,判断链表中是否有环?

图片

这个题比较简单就是使用快慢指针,慢指针一次走一步,快指针一次走两步,如果快指针在走到结尾之前和慢指针相遇了说明有环,如果没相遇则无环。

2. 如果链表有环,则返回环的起点。

这是上题的follow up, 先明确符号含义:

x: 头结点到 entry红点之间的长度;

y: entry 红点到 meet 红点之间的长度;

m:meet红点 到 entry 红点之间的长度;

R:环的整个长度;

t: t时刻快慢指针在meet点相遇。

假设快慢指针在环内的meet点相遇。

快指针走的距离是慢指针走的距离的两倍,有如下两个等式:

2t = x + n* R + y(快指针);

t = x + y (慢指针)

通过这两个等式可以得到 x = n*R - y; 推出 x = m + (n-1)*R。说明相遇之后将慢指针重新放回起点,快指针后面一次只走一步,两个指针再次相遇的点即为entry 入口点。