链表反转是必会的基础操作,LeetCode 92 这道题要求反转从位置 m 到 n 的区间,直接处理很容易把自己绕晕。我自己做的时候发现,只要拆成两步就清晰多了:先写一个反转链表前 n 个节点的递归函数,然后借助虚拟头节点(哨兵)来定位待反转区间,把边界情况交给它。
先实现 reverseN:反转前 n 个节点
这个工具函数是核心。实现递归版很简单,关键是脑子要转过弯来:递归深入到最后再回溯调整指针。
函数签名:ListNode* reverseN(ListNode* head, int n),返回反转后的新头。
递归逻辑分三步:
- 终止条件:n == 1,说明当前节点就是待反转的最后一个,直接返回。
- 递归子问题:记录
head->next为tail,对head->next调用reverseN反转剩下的 n-1 个节点,得到新头。 - 回溯指针调整:把
head->next指向tail->next(即原 tail 的后继),再把tail->next指向head。
效果一目了然:链表 1→2→3→4,n=2 时反转前两个得到 2→1→3→4;n=3 得到 3→2→1→4。
代码写出来就这样:
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
ListNode* reverseN(ListNode* head, int n) {
if (n == 1) {
return head;
}
ListNode* tail = head->next;
ListNode* newHead = reverseN(head->next, n - 1);
head->next = tail->next;
tail->next = head;
return newHead;
}
递归会一直走到待反转的最后一个节点才开始回溯调整,tail 保存了上下文,未反转部分纹丝不动。这版代码虽然用了递归栈,但写起来直接、不易错。如果追求 O(1) 空间,把 reverseN 改成迭代也不难,不过面试时先写递归再口头说明优化就够了。


