编码母题 / 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 } } }
/*
* 题目:反转单链表
* 要求:输入单链表头节点 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 } } }
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)。迭代时只保留前驱、当前和后继引用。