BM4 合并两个排序的链表¶
简单通过率 32.8%python3核心代码模式样例通过牛客 AC链表
讲解章节:链表
一句话
哑节点 + 双指针,每次接走两个当前头里较小的那个。
解题思路¶
这题考什么¶
归并排序的 merge 步骤搬到链表上(归并排序见 排序)。 两条链各自有序,所以结果链的下一个节点一定是两个当前头里较小的那个: 接走它、该链指针后移,直到有一条走空。
链表比数组省事的地方在收尾:剩下那条不用逐个搬, 直接把整段挂到结果链尾巴上就行,这是「只有 next 指针、没有物理相邻性」的红利。
哑节点(dummy head,值无意义的辅助表头)省掉「结果链现在还是空的」这个分支—— 否则每次接入都要先判一次「这是不是第一个节点」。tail 始终指向已建好部分的最后一个节点, 这就是整个循环的不变量。
数据规模与复杂度¶
单链长度 n <= 1000,节点值在 [-1000, 1000],其他语言时限 2 秒。 每个节点恰好被接走一次,时间 O(n + m)、额外空间 O(1)(只重接指针,不新建节点)。 先把两条链的值倒进列表、排序、再建链也是 O((n+m) log(n+m)), 既慢一个 log 又多花 O(n+m) 空间,还浪费了「两条链本来就有序」这个前提。
坑在哪¶
- 循环结束后必须补一句
tail.next = a if a else b。while 的退出条件是 两条链有一条走空,另一条剩下的节点还挂在原处,漏掉这句就直接丢掉一整段后缀; - 取
<=而不是<。相等时优先取第一条,合并是稳定的。本题只比数值, 稳不稳定看不出来,但在「按 key 排序、相同 key 要保持原有先后」的场景里这一笔是致命的; - 两条链都可能为空(样例二就是 {},{})。有哑节点时 dummy.next 从头到尾没被写过, 返回的就是 None,正好是空链表,不需要任何特判;
- 返回 dummy.next 而不是 dummy。dummy 是本地造的辅助节点,它的 val 是 0, 交上去会在结果最前面多出一个凭空的 0。
样例复核¶
{1,3,5} 与 {2,4,6}。依次比较 1<=2 取 1、3>2 取 2、3<=4 取 3、5>4 取 4、5<=6 取 5, 此时 a 走空,把 b 剩下的 6 整段挂上,得到 {1,2,3,4,5,6},与样例一致。
参考实现¶
[:octicons-arrow-left-16: BM3](BM3.md) [BM5 :octicons-arrow-right-16:](BM5.md)