编码母题 / P2 / 经典算法 / 04

反转单链表

重要程度基础热身难度简单预计完成15–20 分钟

题目是什么

输入单链表头节点 head,每个节点含 value 和 next(指向下一节点或 null);原地反转 next 指向并返回新头节点。head 为 null 时返回 null,单节点原样返回,不新建节点。

输入输出示例

输入 1→2→3,返回新头 3,其链表为 3→2→1。

练习起手式与验证

/*
 * 题目:反转单链表
 * 要求:输入单链表头节点 head,每个节点含 value 和 next(指向下一节点或 null);原地反转 next 指向并返回新头节点。head 为 null 时返回 null,单节点原样返回,不新建节点。
 * 示例:输入 1→2→3,返回新头 3,其链表为 3→2→1。
 */
function reverseList(head) {}
console.log(reverseList({ value: 1, next: { value: 2, next: null } })); // 预期:{ value: 2, next: { value: 1, next: null } }
console.log(reverseList(null)); // 预期:null
console.log(reverseList({ value: 1, next: null })); // 预期:{ value: 1, next: null }
console.log(reverseList({ value: 1, next: { value: 2, next: { value: 3, next: null } } })); // 预期:{ value: 3, next: { value: 2, next: { value: 1, next: null } } }

解题思路与实现

展开解题思路

改写当前节点的 next 前先保存后继,始终区分已反转前缀和待处理后缀。

class ListNode {
  constructor(value, next = null) {
    this.value = value;
    this.next = next;
  }
}

function reverseList(head) {
  let previous = null;
  let current = head;
  while (current) {
    const next = current.next;
    current.next = previous;
    previous = current;
    current = next;
  }
  return previous;
}

function fromArray(values) {
  let head = null;
  for (let i = values.length - 1; i >= 0; i -= 1)
    head = new ListNode(values[i], head);
  return head;
}
function toArray(head) {
  const values = [];
  for (let node = head; node; node = node.next) values.push(node.value);
  return values;
}

// 三组以上可直接运行的验证。
console.log(reverseList({ value: 1, next: { value: 2, next: null } })); // 预期:{ value: 2, next: { value: 1, next: null } }
console.log(reverseList(null)); // 预期:null
console.log(reverseList({ value: 1, next: null })); // 预期:{ value: 1, next: null }
console.log(reverseList({ value: 1, next: { value: 2, next: { value: 3, next: null } } })); // 预期:{ value: 3, next: { value: 2, next: { value: 1, next: null } } }

时间复杂度:O(n)。每个链表节点的 next 指针只改写一次。

空间复杂度:O(1)。迭代时只保留前驱、当前和后继引用。

下载原始 JS 文件