标准答案
- 比较两个当前节点,把较小者接到结果尾部并移动对应指针。
- 循环结束时最多有一条链表剩余,直接接到 tail.next。
- 时间复杂度 O(m+n),额外空间 O(1),前提是允许复用原节点。
题目解析
虚拟头节点把“第一次选择结果”与普通循环统一起来,tail 始终表示结果链表的最后一个节点。每次只移动被接入的那条链表,另一条保持不变。
某一条链表耗尽后,另一条剩余部分已经有序且不小于此前接入的节点,可以整体接上,不需要逐个复制。若不允许修改输入,则应创建新节点。
每个节点只比较和连接一次,时间复杂度 O(m+n)。复用节点时额外空间 O(1),创建新链表时则要把新节点空间计入。
代码示例
复用节点的合并实现:
TypeScript
function merge(a: Node | null, b: Node | null) {
const dummy = new Node(0)
let tail = dummy
while (a && b) {
if (a.value <= b.value) { tail.next = a; a = a.next }
else { tail.next = b; b = b.next }
tail = tail.next
}
tail.next = a || b
return dummy.next
}常见误区
- 误区:循环结束后忘记接剩余链表。改正:循环后执行 tail.next = a || b。
- 误区:比较后移动了未被接入的指针。改正:先连接较小节点,再只移动对应的输入指针和 tail。
- 误区:题目不允许修改原链表时仍复用节点。改正:确认所有权要求,必要时创建新节点并说明空间成本。