标准答案

  1. 比较两个当前节点,把较小者接到结果尾部并移动对应指针。
  2. 循环结束时最多有一条链表剩余,直接接到 tail.next。
  3. 时间复杂度 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。
  • 误区:题目不允许修改原链表时仍复用节点。改正:确认所有权要求,必要时创建新节点并说明空间成本。

作者信息