206. 反转链表 (Easy)

专题归类: 04-链表 LeetCode 链接: https://leetcode.cn/problems/reverse-linked-list/


在线做题: 写 Python 代码并运行 · Java 跳转 LeetCode

题目描述

给你单链表的头节点 head,请你反转链表,并返回反转后的链表。

示例:

  • 输入:head = [1,2,3,4,5]
  • 输出:[5,4,3,2,1]

题目详细分析

  • 数据范围: 节点数在 [0, 5000] 范围内,节点值在 [-5000, 5000] 范围内
  • 输入特征: 单向链表,每个节点只有一个 next 指针指向后继
  • 核心约束: 反转后原链表的尾节点变成新链表的头节点,原头节点变成新链表的尾节点(next 指向 None)
  • 隐藏条件: 链表的单向性意味着一旦断开 next 连接就会丢失后续节点,操作前必须先保存
  • 边界条件: 空链表(head 为 None)、只有一个节点的链表

小白版直白理解

就像一串珠子用线串起来,现在要把这串珠子倒过来。你不能直接整串翻转,只能一颗一颗地拆开重新串。

具体怎么做呢?先准备好一根空线(pre = None),然后从第一颗珠子开始,每取下一颗珠子,就把它串到新线的最前面。这样取完所有珠子后,新线上珠子的顺序就是反的了。


解题思路

思路一:迭代法(三指针翻转,推荐)

为什么这样想: 反转一个节点的核心操作是 cur.next = pre,但这样会断开与后续节点的连接。所以需要一个指针 nxt 先保存后续节点。反转完当前节点后,三个指针整体后移一位,重复操作。

关键洞察: pre 始终指向「已反转部分的头节点」,cur 指向「当前待反转的节点」。每次迭代把 cur 从原链表中「摘下来」放到 pre 的前面。

def reverseList(head):
    """迭代法:三指针翻转"""
    pre = None   # 已反转部分的头
    cur = head   # 当前待反转节点
    while cur:
        nxt = cur.next   # 先保存下一个节点,防断链
        cur.next = pre   # 翻转:当前节点指向前一个
        pre = cur        # pre 前移
        cur = nxt        # cur 前移
    return pre  # pre 就是新链表的头节点

思路二:递归法

思路讲解: 递归地反转 head.next 及之后的链表,得到的新链表头节点为 new_head。此时 head.next 指向反转后的最后一个节点,只需让 head.next.next = head 将当前节点接到尾部,再让 head.next = None 断掉原连接。递归的终止条件是空或只有一个节点。

关键洞察: 递归法的核心是「相信子问题能正确反转」,我们只需要处理当前节点和已反转部分尾部的连接。

def reverseList(head):
    """递归法"""
    # 终止条件:空或只有一个节点
    if not head or not head.next:
        return head
    
    new_head = reverseList(head.next)  # 递归反转后续链表
    head.next.next = head              # 将当前节点接到尾部
    head.next = None                   # 断开原 next 指针
    return new_head

思路三:头插法(借助虚拟头节点)

思路讲解: 创建一个虚拟头节点 dummy,然后遍历原链表,每遍历一个节点就用头插法插入到 dummy 后面。最后返回 dummy.next。本质上和迭代法一样,但用 dummy 统一了插入逻辑。

def reverseList(head):
    """头插法"""
    dummy = ListNode(0)
    cur = head
    while cur:
        nxt = cur.next
        # 头插:将 cur 插入到 dummy 后面
        cur.next = dummy.next
        dummy.next = cur
        cur = nxt
    return dummy.next

易错点

  • 断链问题: 执行 cur.next = pre 之前,一定要先保存 nxt = cur.next,否则后续节点丢失
  • 递归返回值: 递归的核心是返回 new_head(即原链表尾节点),不是 head
  • 尾节点处理: 反转后原头节点变成尾节点,要记得将 head.next 设为 None,否则形成环
  • 空链表和单节点: 这两种情况直接返回 head,反转前和反转后结果一样
  • pre 初始化: pre 必须初始化为 None,因为反转后头节点的 next 指向 None

框架提炼

三指针迭代反转模板: 最基础的链表操作,几乎所有链表 Hard 题(K 个一组翻转、反转区间等)的构成基础。

pre, cur = None, head
while cur:
    nxt = cur.next
    cur.next = pre
    pre = cur
    cur = nxt
return pre

递归反转模板:

def reverse(head):
    if not head or not head.next:
        return head
    new_head = reverse(head.next)
    head.next.next = head
    head.next = None
    return new_head

这两个模板必须熟练掌握,因为它们在许多进阶题目中被反复调用。


关联题目