我面试别人的时候有个习惯,热身题固定出LeetCode 206反转链表。这道题难度标的是Easy,常年挂在LeetCode热门100题榜单里,但我在面试现场见过太多“五分钟默写出代码、一句话解释不清”的候选人。你说他会不会?会写。你问他为什么要有那个临时变量,为什么最后要返回prev而不是head,很多人就开始眼神飘忽。
这篇文章我不打算只贴一份题解就算了。我要把206从链表的内存结构讲起,讲清楚迭代和递归的本质,讲透边界条件,最后把从206延伸出去的一片链表题串联起来。如果你刚开始刷LeetCode,这篇能帮你真正建立链表题的直觉;如果你准备面试,这篇能给你的讲解深度加一层保险。
1. 为什么我说206是所有链表题的“第一块敲门砖”
1.1 题目到底在问什么
题目原文很简单:给定单链表的头节点head,反转链表,并返回反转后的链表头。
示例更简单:
- 输入:head = [1,2,3,4,5],输出:[5,4,3,2,1]
- 输入:head = [1,2],输出:[2,1]
- 输入:head = [],输出:[]
而且题目后面还带了一句经典追问:你能用迭代和递归两种方法实现吗?这句话在LeetCode上不算太显眼,但它恰恰是面试官最常借用来延伸考察的点。做这题的时候如果只背了一种解法,等到追问的时候就会很被动。
1.2 一道Easy题为什么值得写长文
先说结论:206在链表类题目里的地位,就像数组里的二分查找、字符串里的双指针、动态规划里的背包问题。它看起来简单,但它把链表操作里最核心的东西全占了。
第一,它是热门100题成员。在LeetCode上,206和最长回文子串、目标和这些大流量题目一样,是几乎所有刷题者都会碰到的一道。很多人把它当成“签到题”刷掉就继续赶路,但其实它的价值被严重低估了。
第二,它是后续一大票中等、困难题的地基。你把链表题想象成一栋楼,206就是承重墙。后面遇到的很多题,最后都要调用“反转一段链表”这个子操作。92题反转链表II、25题K个一组翻转链表、234题回文链表、143题重排链表,无一例外都建立在这个基本能力上。
第三,迭代和递归两种解法,代表了两种完全不同的算法思维。迭代是典型的指针操作,考察你对引用、对“谁指向谁”的掌控力;递归则考察你能不能跳出细节,用“信任函数”的方式思考。这两种思维在更复杂的树、图、回溯问题里同样适用,刷206正好能用最小成本把这两种思维都练一遍。
第四,面试里它是完美的“抛砖引玉”题。我在模拟面试时喜欢拿206当第一题,等候选人写完后,我会追加几个限制,比如“链表很长,递归会不会栈溢出”“那改成反转中间一段呢”。如果候选人真懂指针机制,这几个追问没问题;如果只是背了答案,几个问题下来基本就露馅了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 链表的内存结构与“反转”到底在反转什么
2.1 单链表在内存里长什么样
写任何代码之前,先把链表在内存里的形态搞清楚。这是很多人刷了很久链表题还是没有手感,看到指针就发怵的根本原因。
单链表由一组节点组成,每个节点包含两个字段:val和next。val是节点存的值,next是一个引用,指向下一个节点。Python里的定义长这样:
python复制class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
Java版本:
java复制public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
关键点在于:链表在内存里不是连续存储的。数组是一块连续内存,你按下标能直接算出第i个元素的位置,所以可以随机访问;而链表的节点零零散散分布,彼此靠next指针串联,你想访问第3个节点,必须从head开始一个个走过去
