LeetCode面试HOT100—— 206. 反转链表

反转链表的头插法解析

反转链表代码超详细解析(头插法思路)

这段代码是反转单链表的 迭代最优解(时间复杂度O(n)、空间复杂度O(1)),核心思路是用「头插法」把原链表的节点逐个"搬到"新链表的头部,最终新链表的头就是反转后的结果。下面从「核心逻辑→逐行拆解→步骤演示→关键细节」帮你彻底吃透。

一、先明确两个核心概念

1. 单链表的结构

每个 ListNode 节点包含两部分:

  • val:节点存储的值;

  • next:指针(引用),指向后一个节点(链表末尾节点的 nextnull)。

原链表示例:1 → 2 → 3 → 4 → nullhead 指向节点1),反转目标:null ← 1 ← 2 ← 3 ← 4(新头指向节点4)。

2. 算法核心思路(头插法)

把原链表的节点 从前往后逐个取出,每次都插入到「新链表的头部」,相当于反向构建新链表:

  • pre 记录「新链表的头节点」(初始为空,因为新链表还没节点);

  • cur 记录「原链表当前要处理的节点」(初始为原链表头 head);

  • nxt 临时保存「原链表的下一个节点」(防止处理当前节点时,原链表"断开");

  • 循环执行:取当前节点→插入新链表头部→移动指针,直到原链表遍历完。

二、代码逐行拆解(带注释)

Java 复制代码

三、分步演示(用示例链表 1→2→3→4→null

我们用表格跟踪每一步 precurnxt 的值和链表结构变化,直观理解反转过程。

初始状态(循环开始前)

指针 指向节点 链表结构(原链表) 新链表结构
pre null 1 → 2 → 3 → 4 → null null
cur 1
nxt 未定义

第一次循环(处理节点1)

  1. ListNode nxt = cur.next;nxt = 2(保存原链表下一个节点);

  2. cur.next = pre; → 节点1的next指向prenull),此时节点1:1→null

  3. pre = cur;pre = 1(新链表头更新为节点1,新链表:1→null);

  4. cur = nxt;cur = 2(原链表当前节点向后移)。

指针 指向节点 原链表剩余部分 新链表结构
pre 1 2 → 3 → 4 → null 1 → null
cur 2
nxt 2

第二次循环(处理节点2)

  1. nxt = cur.next;nxt = 3(保存节点2的下一个节点);

  2. cur.next = pre; → 节点2的next指向pre(1),此时节点2:2→1

  3. pre = cur;pre = 2(新链表头更新为节点2,新链表:2→1→null);

  4. cur = nxt;cur = 3

指针 指向节点 原链表剩余部分 新链表结构
pre 2 3 → 4 → null 2 → 1 → null
cur 3
nxt 3

第三次循环(处理节点3)

  1. nxt = cur.next;nxt = 4

  2. cur.next = pre; → 节点3的next指向2,节点3:3→2

  3. pre = cur;pre = 3(新链表:3→2→1→null);

  4. cur = nxt;cur = 4

指针 指向节点 原链表剩余部分 新链表结构
pre 3 4 → null 3 → 2 → 1 → null
cur 4
nxt 4

第四次循环(处理节点4)

  1. nxt = cur.next;nxt = null(节点4是原链表最后一个节点,下一个为null);

  2. cur.next = pre; → 节点4的next指向3,节点4:4→3

  3. pre = cur;pre = 4(新链表:4→3→2→1→null);

  4. cur = nxt;cur = null(原链表遍历结束,循环终止)。

指针 指向节点 原链表剩余部分 新链表结构
pre 4 null 4 → 3 → 2 → 1 → null
cur null
nxt null

循环结束,返回pre

此时pre指向新链表的头节点4,反转后的链表为 4→3→2→1→null,完全符合预期。

四、关键细节与避坑点

1. 为什么必须用nxt保存cur.next

如果不保存,执行 cur.next = pre 后,cur.next 就指向了新链表(而非原链表的下一个节点),后续无法再找到原链表的剩余节点,导致链表"断开",遍历终止。nxt 相当于"临时备忘录",记录原链表的后续路径。

2. 循环终止条件为什么是cur != null

cur 是原链表的"当前处理节点":

  • cur 不为null时,说明还有节点没处理;

  • curnull时,原链表所有节点都已插入新链表,循环结束。

3. 为什么返回pre而不是cur

循环结束时,cur 已经指向null(原链表遍历完),而 pre 指向的是最后一个处理的节点(原链表的尾节点,新链表的头节点),所以返回pre才是反转后的链表头。

4. 边界情况是否覆盖?

  • 空链表(head = null):cur 初始为null,循环不执行,返回pre = null,正确;

  • 单节点链表(head = 1→null):循环执行1次,pre 最终指向1,返回1,正确。

五、总结

这段代码的核心是「头插法迭代反转」:

  1. 用三个指针(precurnxt)分工明确:pre 管新链表,cur 管原链表当前节点,nxt 管原链表后续节点;

  2. 每一步都围绕"取节点→反转指针→移动指针",逻辑闭环;

  3. 时间复杂度O(n)(遍历一次链表),空间复杂度O(1)(仅用三个指针,不额外占用空间),是最优解法。

记住一句话:"保存下一个,反转当前,移动双指针",就能轻松默写这段代码!如果还是不理解,可以动手画一画每一步的指针变化,可视化后会瞬间清晰。

相关推荐
子一!!1 小时前
哈希桶,元素插入逻辑实现
算法·哈希算法
敲代码的嘎仔1 小时前
LeetCode面试HOT100——160. 相交链表
java·学习·算法·leetcode·链表·面试·职场和发展
吃着火锅x唱着歌1 小时前
LeetCode 454.四数相加II
算法·leetcode·职场和发展
雨中飘荡的记忆1 小时前
设计模式之适配器模式详解
java·设计模式·适配器模式
丝斯20111 小时前
AI学习笔记整理(19)—— AI核心技术(深度学习3)
人工智能·笔记·学习
自然语1 小时前
深度学习时代结束了,2025年开始只剩下轮廓
数据结构·人工智能·深度学习·学习·算法
海天一色y1 小时前
Leetcode07-整数反转
算法
im_AMBER1 小时前
Leetcode 66 几乎唯一子数组的最大和
数据结构·笔记·学习·算法·leetcode
Aspect of twilight1 小时前
华为华为AI岗实习面试算法题
算法·华为·面试