考研学习
解题方法数据结构

数据结构第 2 章:线性表

408 数据结构「线性表」复习:核心知识点、真题题型、通用解法与易错点。

Last updated on

本章依据本站 408 真题「第 2 章 线性表」和对应的 408 模拟选择题「第 2 章 线性表」 整理。站内真题把本章分成“顺序存储”和“链式存储”,真题尤其集中在数组原地算法、双指针、单链表综合操作、双链表指针修改;模拟题又补充了静态链表和不同存储结构的复杂度判断。(Any Docs)

这章非常重要,因为它实际上是整个数据结构“算法题基本功”的起点。后面的树、图、查找、排序都会反复用到这里形成的几种思维:

数组:下标、原地交换、双指针、空间换时间。 链表:找位置、断链、保存后继、重新连接。


一、本章到底要学什么?

先建立完整地图。

知识块408重要性主要题型
线性表基本概念★★定义、逻辑关系
顺序表特点★★★插入删除复杂度、随机访问
顺序表算法★★★★★原地逆置、双指针、特殊数组算法
单链表基本操作★★★★★插入、删除、遍历
单链表综合算法★★★★★快慢指针、逆置、拆分、合并
双链表★★★★插入删除语句判断
循环链表★★★首尾特殊情况
静态链表★★数组下标模拟指针
顺序表与链表比较★★★★时间复杂度判断

一个关键结论是:

真正需要重点练的不是“顺序表插入代码怎么写”,而是怎么根据题目条件设计一个尽可能快的算法。

站内的 2010、2011、2013、2018、2019、2020 真题尤其能体现这一点。(Any Docs)


二、线性表的基本概念

线性表可以写成

其特点是:

除第一个元素外,每个元素有唯一直接前驱;除最后一个元素外,每个元素有唯一直接后继。

注意:

“线性”说的是逻辑关系,不是物理存储方式。

例如:

顺序表逻辑上是

物理上通常也连续。

而链表逻辑上仍然是

但三个结点在内存中完全可以位于三个毫不相关的位置。

所以考试看到“地址乱七八糟”,千万不要按地址大小判断元素顺序,必须沿 next 找。

这正是 2016 年真题考查的内容。


三、顺序表和链表的根本差别

这是后面几乎所有复杂度题的基础。

操作顺序表单链表
按序号访问第 个元素
按值查找
已知位置插入通常 已知前驱后
已知结点删除需移动元素 若知道前驱可
存储密度高较低
扩容可能需要重新分配动态申请即可
随机访问支持不支持

最核心的一句话:

顺序表擅长“访问”,链表擅长“修改链接”。

但一定注意:

“链表插入删除是 ”这句话有条件。

必须是已经找到插入或删除位置。

例如要删除单链表第 个结点,首先找到第 个结点通常就需要

所以整个操作仍然是


四、题型一:数组原地变换——逆置法

真题:2010 年循环左移

题目核心:

有数组

要循环左移 个位置,变成

要求时间和空间尽可能高效。(Any Docs)

这是一道极其重要的“原地数组变换”模板题。

设

原序列就是

目标是

利用逆置:

于是三步:

再得到

最后整体逆置:

例如

左移 位。

先逆置前 3 个:

再逆置后 4 个:

全部逆置:

复杂度:

站内也给出的正是“三次逆置”方案。(Any Docs)

这一题真正要学什么?

以后看到:

“循环移动”“前后两段互换”“数组原地调整”

第一反应就是:

例如右移 位,可以直接变形为左移

位。


五、题型二:两个有序数组——不要傻傻合并

真题:2011 年两个等长升序序列的中位数

题目:

两个长度均为 的升序数组 ,定义两个序列合并后的第 小元素为中位数,要求尽可能高效地求出来。(Any Docs)

最容易想到:

两个数组归并。

复杂度:

空间可以做到

但这还不是最优。

因为题目给了一个极重要条件:

两个数组本身已经有序。

于是可以像二分查找一样不断排除一半。

取两个数组当前区间的中位数

和

若

直接得到答案。

如果

那么总体中位数不可能出现在:

的过小部分,以及 的过大部分。

于是同时舍弃两边等量元素。

候选规模约变为原来的

所以

最终:

空间:

站内真题解析也采用了这种二分缩小候选范围的方法。(Any Docs)


这里有一个非常重要的考试意识

只要看到:

“有序”

就应该立刻想到:

而不是直接写双层循环。


六、题型三:主元素——“不同元素互相抵消”

真题:2013 年主元素

题目定义:

若某元素 出现次数

则称 为主元素。

例如

主元素为 。

要求尽可能高效地找到主元素。(Any Docs)


解法:Boyer-Moore 多数投票

关键性质:

若主元素出现超过一半,那么即使不断执行:

删除两个值不同的元素

最终主元素也不可能被完全消掉。

维护:

candidate:候选主元素

count:票数

扫描数组。

遇到相同元素:

遇到不同元素:

若

则重新选择候选。

例如:

过程可以理解为:

抵消;

抵消;

最终因为 数量超过其他所有元素总和,所以 一定留下。


但是为什么必须再扫描一次?

因为投票算法只能得到:

“如果主元素存在,那么这个 candidate 一定是它。”

不保证主元素一定存在。

因此还要重新统计:

如果

才真正返回它。

复杂度:

空间:

站内真题也特别强调了“第一趟筛选,第二趟验证”。(Any Docs)


七、题型四:利用元素范围建立“下标映射”

这是408算法题非常喜欢的一类思想。

真题:2018 年最小未出现正整数

题目:

给定长度为 的整数数组,找其中没有出现的最小正整数。

例如:

答案:

而

答案:

(Any Docs)


第一步:先缩小答案范围

这是这题最关键的一步。

长度只有 。

如果

全部出现,那么答案最多是

否则答案就在

中。

因此真正关心的只有:

其他数字,例如:

全部可以忽略。


标准思维一:标记数组

建立数组 seen[n+1]。

若出现数字 :

最后找到第一个没有出现的。

复杂度:

空间:

这是考场上非常稳的一种做法。


更进一步:直接利用原数组

本站里的解析采用了更强的原地做法:

把

放到

的位置。

于是理想状态:

最后扫描:

若第一个

那么答案就是

如果全部满足,则答案:

这样能够达到

时间,

额外空间。(Any Docs)

这一类型的统一思想

以后看到:

元素取值范围很小

例如:

或者

都应该立刻想到:

后面的 2015 年链表删除重复绝对值,还是这个思想。


八、题型五:多个有序数组——多指针贪心

真题:2020 年三个集合最小距离

有三个升序数组

选择

定义

求最小值。(Any Docs)

例如题目给出的:

最优三元组:


第一关键:化简距离公式

设三者排序后:

那么

所以

即

因此问题完全变成:

如何让三个当前元素的最大值和最小值尽可能接近?


第二关键:为什么移动最小值?

假设当前:

距离取决于:

如果移动 或 :

它们只会继续增大,因为数组是升序。

这样不可能减小当前最小值 与最大值之间的差距。

所以唯一可能改善答案的方法:

于是三个指针只向前走。

总复杂度:

额外空间:

这正是站内真题给出的算法。(Any Docs)


九、顺序表算法题总结:看见什么条件想到什么算法?

题目特征第一反应
原地循环移动分段逆置
有序数组双指针 / 二分
出现次数超过一半Boyer-Moore
元素范围有限标记数组 / 原地哈希
多个有序集合多指针扫描
要求 空间交换、逆置、指针,而不是复制数组

到这里,顺序存储部分真正需要掌握的核心思维已经完整了。


十、链表第一大题型:看懂“地址”而不是看元素排列

2016 真题:根据物理地址插入结点

题目给出:

地址元素链接地址
1000Ha1010H
1004Hb100CH
1008Hc1000H
100CHdNULL
1010He1004H

表头元素为 。

所以从 开始:

这才是真正的逻辑顺序。

现在结点 放在地址 1014H,插到 之间。(Any Docs)

局部原来:

现在:

所以:

而

不变。

答案:


模拟题:删除 a

网站模拟题进一步要求在同一个结构里删除 。

原来:

删除后:

因此:

而 仍然指向 :

答案是

。(Any Docs)

这两道题组合起来非常值得记。

核心不是背地址,而是:


十一、链表第二大题型:插入删除的语句顺序

这是本章选择题最高频陷阱之一。

核心原则:

永远不要先覆盖掉以后还要用的指针。


十二、单链表头插法

模拟题:

带头结点单链表,头指针为 。希望插入顺序与链中顺序相反,应如何插入新结点 ?(Any Docs)

显然是头插法:

p->next = L->next;
L->next = p;

注意顺序绝对不能交换。

如果写:

L->next = p;
p->next = L->next;

第二句中的

L->next

已经变成 。

结果:

p->next = p;

形成自环。

这是典型考试陷阱。


十三、双链表删除——四个指针看起来复杂,其实只有两条边

2016 真题

删除双向循环链表中 指向的结点。(Any Docs)

删除前:

删除后:

需要修改:

以及:

即:

p->next->prev = p->prev;
p->prev->next = p->next;
free(p);

答案 D。(Any Docs)

最好不要死背

画图:

A <----> p <----> B

删掉 :

A <------------> B

再问:

谁的 next 变了?

A。

谁的 prev 变了?

B。

立刻得到答案。


十四、双链表插入——最容易考“修改次序”

2023 真题

要在 之后插入 。

题目已经执行:

s->next = p->next;
p->next = s;

问还需要什么?(Any Docs)

原来:

目标:

执行前两句后:

但:

还没正确设置,

而

仍指向 。

此时有:

s->next->prev

其实仍然是 。

所以:

s->prev = s->next->prev;
s->next->prev = s;

答案 C。(Any Docs)

这里特别容易误选:

p->next->prev = s;

为什么错?

因为执行了:

p->next = s;

以后

p->next

就是 。

所以

p->next->prev = s;

实际上成为:

s->prev = s;

形成自指。


十五、模拟题:在 p 前插入 x

站内模拟题把 2023 真题反过来:

双向循环链表,在 前插入 。(Any Docs)

设:

目标:

正确顺序:

x->next = p;
x->prev = p->prev;
p->prev->next = x;
p->prev = x;

为什么最后才:

p->prev = x;

因为旧的

p->prev

还要帮助找到 。

这就是链表语句排序题的统一法则:


十六、循环链表:重点不是“循环”,而是边界

2021 真题

带头结点非空单循环链表。

为头指针,

为尾指针。

删除第一个数据结点。(Any Docs)

设第一个结点为 :

q = h->next;
h->next = q->next;

通常这样就够了。

但是题目还有一个特殊情况:

链表只有一个数据结点。

此时

删除后尾指针不能继续指向已经释放的 。

因此必须:

if (p == q)
    p = h;

最后:

free(q);

所以答案 D。(Any Docs)


这种题最爱考什么?

不是主体算法。

而是:

首结点、

尾结点、

只有一个结点。

所以做链表选择题最后一定要问自己:

“如果链表只有一个元素,还成立吗?”


十七、链表代码执行结果题

2024 真题

给定非首非尾结点 ,执行:

q = p->next;
p->next = q->next;
q->next = h->next;
h->next = q;

问结果是什么。(Any Docs)

不要整体看。

逐段解释。

前两句:

q = p->next;
p->next = q->next;

原来:

变成:

所以 被摘下来。

后两句:

q->next = h->next;
h->next = q;

这是标准头插。

所以最终:

答案 D。(Any Docs)


十八、链表代码阅读的万能方法

不要在脑子里直接执行四五行指针语句。

应该每执行一条就画:

A -> B -> C -> D

例如:

q = p->next;

就在图上标记 。

然后:

p->next = q->next;

把对应箭头擦掉重画。

408 指针题其实是“画箭头题”,不是 C 语言题。


十九、链表算法第一大模板:快慢指针

2009 真题:倒数第 k 个结点

题目:

带头结点的单链表,只给头指针 list,要求不改变链表,尽可能高效地查找倒数第 个结点。(Any Docs)


普通方法

先遍历一次求长度:

再找到:

位置。

需要两趟。

虽然仍然是

但可以更漂亮。


快慢指针

设置:

都从首元结点出发。

让 fast 先走 步。

这样二者保持距离:

然后一起移动。

当

时,

slow 正好是倒数第 个结点。

例如链表:

找倒数第 2 个。

fast 先走 2 步。

之后同步前进,fast 到 NULL 时:

答案正确。

复杂度:

空间:

站内真题也是这一方案。(Any Docs)


二十、快慢指针还能解决哪些题?

这是必须扩展出去的。

找链表中点:

fast 每次走两步,

slow 每次走一步。

当 fast 到尾部时:

就在中间。

判断环:

还是 fast 两步、slow 一步。

有环一定会相遇。

寻找倒数第 个:

保持两个指针相差 个位置。

所以快慢指针的本质不是固定套路,而是:


二十一、链表算法第二模板:尾部对齐

2012 真题:两个单词的公共后缀

题目用链表保存 "loading" 和 "being"。

如果两个单词有相同后缀,则相同后缀结点共享存储空间。

要求找到公共后缀的起点。(Any Docs)

例如:

loading ─┐
         i -> n -> g -> NULL
being ───┘

注意:

这里不是字符相同。

而是两个指针最终指向同一个物理结点。


为什么不能两个指针直接同时走?

因为链表长度可能不同。

例如:

A: x -> x -> x -> c -> d
B:           y -> c -> d

如果同时从表头开始,很可能永远无法同时到公共结点。


正确办法:尾部对齐

设长度分别:

长链表先走:

步。

之后两个指针到尾结点的距离相同。

然后同步走。

第一次满足:

即找到公共后缀起始结点。

复杂度:

空间:

。(Any Docs)


二十二、“倒数第 k 个”和“公共后缀”其实是一类题

表面上:

2009 年问倒数第 个;

2012 年问公共结点。

但底层思想完全一样:

2009:

人为制造距离

2012:

人为消除长度差

一旦理解这一层,两道题就不需要分别背。


二十三、链表算法第三模板:辅助数组换时间

2015 真题

单链表有 个整数,且

要求对于绝对值相同的结点只保留第一次出现者,其余删除。(Any Docs)

例如:

由于:

后面重复的都应该删掉。


如果不用额外空间

每出现一个元素,都向前查是否出现过。

最坏:


利用题目条件

因为:

所以绝对值只能:

建立:

遇到:

检查:

若没出现:

保留。

若出现:

删除。

复杂度:

空间:

。(Any Docs)


二十四、删除链表结点时为什么通常需要 pre?

设:

pre -> p -> q

要删除 。

需要:

pre->next = p->next;
free(p);
p = pre->next;

因为单链表不能直接由 找前驱。

所以扫描过程中通常同时维护:

pre
p

这是所有“边遍历边删除”问题的标准结构。


二十五、本章最综合真题:2019 年链表重排

这一题非常值得反复练。

题目

原链表:

要求原地变成:

要求空间:

时间尽可能高效。(Any Docs)


二十六、先分析目标,而不是直接写代码

假设:

目标:

观察发现:

从左边取一个,

再从右边取一个。

但单链表只能向后访问。

无法直接:

倒着访问。

怎么办?

把后半段逆置。


二十七、第一步:找链表中点

使用快慢指针:

slow 每次:

步,

fast 每次:

步。

对于:

最后把链表拆成:

和

。


二十八、第二步:逆置后半段

把:

变成:

这是单链表必须掌握的核心代码:

prev = NULL;
cur = head;

while (cur != NULL) {
    next = cur->next;
    cur->next = prev;
    prev = cur;
    cur = next;
}

核心只有四个字:

存、断、接、移

先保存:

next = cur->next;

然后反转:

cur->next = prev;

再移动:

prev = cur;
cur = next;

二十九、第三步:交替合并

现在有:

1 -> 2 -> 3
6 -> 5 -> 4

交替取:

即可。

整个过程:

找中点:

逆置:

合并:

所以:

额外空间只有几个指针:

这就是站内 2019 真题给出的“三阶段算法”。(Any Docs)


三十、为什么2019这题特别重要?

因为它实际上把单链表三大核心算法一次性全考了:

因此,本章最值得完整默写的一道算法题是:

2019 年这道题排第一。


三十一、2013 真题:两个升序链表合并成降序链表

题目:

两个长度分别为 的升序链表,合并成一个长度为 的降序链表。

问最坏时间复杂度。(Any Docs)

两个升序链表:

1 -> 4 -> 8
2 -> 3 -> 9

每次比较两个首结点。

取较小者后,可以采用头插法。

例如依次取:

不断头插以后,结果自然反过来:

每个结点最多访问一次:

而:

因此渐进意义下:

所以答案 D。(Any Docs)


三十二、这题又说明一个容易错的复杂度问题

很多同学看到:

就在选项中找

找不到就慌。

要会判断渐进等价。

因为:

所以:

与

在这里属于同一级。


三十三、静态链表

这部分真题很少,但模拟题有补充。

静态链表本质:

不用真正的指针,而是用数组下标表示“下一个结点的位置”。

例如:

typedef struct {
    DataType data;
    int link;
} SListNode;

如果结点 :

S[i].link = 7;

意思就是:

下一个逻辑结点存储在

。

因此模拟题问:

已知逻辑第 个结点的数组下标为 ,第 个结点的数据是什么?(Any Docs)

答案:

S[S[i].link].data

而绝对不能写:

S[i+1].data

因为静态链表的:


三十四、静态链表还可能考“备用链表”

站内模拟题还有一道:

主静态链表和空闲链表同时存在,删除主链表中的结点后,把释放位置头插到空闲链表中。(Any Docs)

本质就是同时完成两件事。

主链表中:

pre -> x -> next

删除:

pre -> next

随后把 插到空闲链表:

avail -> oldFree

变:

avail -> x -> oldFree

所以静态链表不要觉得特殊。

它本质仍是:


三十五、顺序表与链表复杂度判断题

站内模拟题问:

哪些操作可以在

完成,其中正确答案是双向循环链表删除首个数据结点。(Any Docs)

为什么?

双向循环链表可以直接得到前驱、后继。

修改有限个指针即可:

而只有头指针的普通单链表,如果要在末尾添加:

需要先找到尾结点:

单向循环链表如果没有尾指针,要修改尾部关系,也可能需要遍历寻找尾结点:

。

所以复杂度判断的核心不是:

“它是不是链表?”

而是:

当前给了哪些指针?能不能直接取得目标结点或其前驱?


三十六、第 2 章所有链表题,可以压缩成四种操作

以后遇到陌生链表算法,不妨先判断它本质属于哪种。

底层操作典型题
找位置倒数第 个、中点、公共结点
改链接插入、删除、移动结点
改方向链表逆置
重组合合并、拆分、交叉排列

2019 综合题就是:

所以复杂链表算法一般不是一种全新的算法,而是几个基础操作拼起来。


三十七、408链表算法题写代码的通用框架

假设带头结点:

typedef struct LNode {
    int data;
    struct LNode *next;
} LNode;

以后可以把很多题理解成以下几类模板。

遍历

LNode *p = L->next;

while (p != NULL) {
    // process p
    p = p->next;
}

边遍历边删除

LNode *pre = L;
LNode *p = L->next;

while (p != NULL) {
    if (should_delete(p)) {
        pre->next = p->next;
        free(p);
        p = pre->next;
    } else {
        pre = p;
        p = p->next;
    }
}

逆置

LNode *pre = NULL;
LNode *p = head;

while (p != NULL) {
    LNode *q = p->next;
    p->next = pre;
    pre = p;
    p = q;
}

快慢指针

slow = first;
fast = first;

while (fast != NULL && fast->next != NULL) {
    slow = slow->next;
    fast = fast->next->next;
}

这四块最好达到不用思考就能写出来的程度。


三十八、链表算法最容易丢分的地方

第一类是丢后继。

例如错误:

p->next = pre;
p = p->next;

因为执行第一句后,

p->next

已经变成原来的前驱了。

原来的后继找不到。

所以一定提前:

q = p->next;

第二类是释放后继续访问。

错误:

free(p);
p = p->next;

p 已经释放。

正确做法应该提前保存后继,或者:

pre->next = p->next;
free(p);
p = pre->next;

第三类是头结点和首元结点混淆。

带头结点:

L -> a1 -> a2 -> ...

其中:

指向的是头结点,

真正的第一个元素是:

L->next

第四类是比较“数据相同”还是“结点相同”。

2012 公共后缀问题要求比较:

也就是地址相同。

不是:

否则两个不同位置恰好字符相同,也会被误认为公共结点。(Any Docs)


三十九、把整章真题按“算法思想”重新分类

这样复习会比按照教材目录背题更有效。

思想对应站内真题
分段逆置2010 数组循环左移
二分排除2011 两个升序序列中位数
抵消法2013 主元素
下标映射/原地哈希2018 最小未出现正整数
多指针贪心2020 三集合最小距离
链表归并+头插2013 升序链表合成降序
地址追踪2016 单链表内存布局
双链表修改2016、2023
循环链表边界2021
链表语句模拟2024
前后指针间距2009 倒数第 个
尾端对齐2012 公共后缀
辅助数组2015 删除绝对值重复
找中点+逆置+交替合并2019 链表重排

这些题基本已经覆盖了408线性表算法的主干。(Any Docs)


四十、一个非常重要的“条件 → 方法”映射

这是建议真正记住的东西。

看到:

想到:

看到:

想到:

看到:

想到:

看到:

想到:

看到:

想到:

看到:

想到:

看到:

想到:

看到:

想到:

这比背20道题有价值。


四十一、可能出现的拓展考法

根据这些真题的命题方式,很容易进一步组合出新的算法题。

预测一:判断单链表是否中心对称

例如:

判断是否回文。

最优方法正好由2019真题变形而来:

找中点:

逆置后半段:

前后同时比较:

所以:

这实际上就是2019题的:

少了最后的交替合并。


四十二、预测二:两个单链表是否相交

2012公共后缀题的直接变形。

如果两个无环单链表相交,那么从交点开始:

链完全相同。

可以计算长度:

长链表先走:

随后同步前进。

若存在:

则相交。

复杂度:

空间:

。


四十三、预测三:删除链表倒数第 k 个结点

把2009年:

找倒数第 个

与删除操作组合。

快指针先走 或 步,让慢指针最终停在目标结点前驱。

然后:

q = slow->next;
slow->next = q->next;
free(q);

所以考研出题非常可能不是创造一个新算法,而是:


四十四、预测四:有序链表去重

例如:

变:

因为已经有序,所以相同元素必连续。

不需要2015题那样的辅助数组。

只需要比较:

与:

时间:

空间:

这说明题目中的“有序”条件可以让算法发生巨大变化。


四十五、预测五:两个有序链表的交集

例如:

求:

可以使用两个指针。

若:

移动 。

若:

移动 。

若相等:

记录并同时移动。

复杂度:

这是2020年多数组指针思维与链表结构的组合。


四十六、本章算法题怎样分析时间复杂度?

链表特别容易被代码里的多个 while 吓到。

例如2019:

第一段:

第二段:

第三段:

不是:

而是:

只有嵌套循环才通常乘起来。

例如:

for each p
    scan from beginning

才可能:

所以判断复杂度时先问:

这些循环是顺序执行还是嵌套执行?


四十七、本章考试优先级

如果现在准备408,本文将把这一章复习顺序排成下面这样:

  1. 单链表插入、删除、逆置必须完全掌握。
  2. 快慢指针必须掌握:中点、倒数第 个。
  3. 2019链表重排完整掌握。
  4. 双链表插入删除语句必须会画图判断。
  5. 有序数组的双指针、二分思想必须掌握。
  6. 利用元素范围建立辅助数组/下标映射必须有敏感度。
  7. 静态链表理解即可,不值得投入与前几项相同的时间。

从站内收录的历年题来看,这个优先级也与真题覆盖非常吻合:顺序存储主要以算法题出现,而链式存储既有大量选择题,也反复出现完整算法设计题。(Any Docs)


四十八、最后把第 2 章压缩成一张“考场思维图”

遇到数组:

有序:

无序但值域小:

要求:

则:


遇到链表:

先问:

找位置:

倒数第 个:

中点:

公共结点:

改结构:

删除:

插入:

逆置:

复杂重排:


第 2 章真正需要形成的能力

如果学完这一章只是会说“顺序表随机访问 ,链表插入 ”,远远不够。

真正达到408要求,应该做到:

看到2010循环移位,能想到分段逆置;

看到2011两个有序数组,能意识到不能浪费有序性;

看到2013主元素,能想到抵消;

看到2015的

马上意识到值域可以映射为下标;

看到倒数第 个,马上想到两个指针保持距离;

看到公共后缀,马上想到尾部对齐;

看到2019的

能够自己拆成:

做到这一层,线性表的算法题基本就从“每一道都是新题”,变成了“几套模板的重新组合”。这也是这一章最重要的学习目标。(Any Docs)

On this page

一、本章到底要学什么?二、线性表的基本概念三、顺序表和链表的根本差别四、题型一:数组原地变换——逆置法真题:2010 年循环左移这一题真正要学什么?五、题型二:两个有序数组——不要傻傻合并真题:2011 年两个等长升序序列的中位数这里有一个非常重要的考试意识六、题型三:主元素——“不同元素互相抵消”真题:2013 年主元素解法:Boyer-Moore 多数投票但是为什么必须再扫描一次?七、题型四:利用元素范围建立“下标映射”真题:2018 年最小未出现正整数第一步:先缩小答案范围标准思维一:标记数组更进一步:直接利用原数组这一类型的统一思想八、题型五:多个有序数组——多指针贪心真题:2020 年三个集合最小距离第一关键:化简距离公式第二关键:为什么移动最小值?九、顺序表算法题总结:看见什么条件想到什么算法?十、链表第一大题型:看懂“地址”而不是看元素排列2016 真题:根据物理地址插入结点模拟题:删除 a十一、链表第二大题型:插入删除的语句顺序十二、单链表头插法十三、双链表删除——四个指针看起来复杂,其实只有两条边2016 真题最好不要死背十四、双链表插入——最容易考“修改次序”2023 真题十五、模拟题:在 p 前插入 x十六、循环链表:重点不是“循环”,而是边界2021 真题这种题最爱考什么?十七、链表代码执行结果题2024 真题十八、链表代码阅读的万能方法十九、链表算法第一大模板:快慢指针2009 真题:倒数第 k 个结点普通方法快慢指针二十、快慢指针还能解决哪些题?二十一、链表算法第二模板:尾部对齐2012 真题:两个单词的公共后缀为什么不能两个指针直接同时走?正确办法:尾部对齐二十二、“倒数第 k 个”和“公共后缀”其实是一类题二十三、链表算法第三模板:辅助数组换时间2015 真题如果不用额外空间利用题目条件二十四、删除链表结点时为什么通常需要 pre?二十五、本章最综合真题:2019 年链表重排题目二十六、先分析目标,而不是直接写代码二十七、第一步:找链表中点二十八、第二步:逆置后半段二十九、第三步:交替合并三十、为什么2019这题特别重要?三十一、2013 真题:两个升序链表合并成降序链表三十二、这题又说明一个容易错的复杂度问题三十三、静态链表三十四、静态链表还可能考“备用链表”三十五、顺序表与链表复杂度判断题三十六、第 2 章所有链表题,可以压缩成四种操作三十七、408链表算法题写代码的通用框架遍历边遍历边删除逆置快慢指针三十八、链表算法最容易丢分的地方三十九、把整章真题按“算法思想”重新分类四十、一个非常重要的“条件 → 方法”映射四十一、可能出现的拓展考法预测一:判断单链表是否中心对称四十二、预测二:两个单链表是否相交四十三、预测三:删除链表倒数第 k 个结点四十四、预测四:有序链表去重四十五、预测五:两个有序链表的交集四十六、本章算法题怎样分析时间复杂度?四十七、本章考试优先级四十八、最后把第 2 章压缩成一张“考场思维图”第 2 章真正需要形成的能力