链表操作的递归思维
01 递归反转整个链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:输入:head = [1,2,3,4,5]输出:[5,4,3,2,1]示例 2:输入:head = [1,2]输出:[2,1]示例 3:输入:head = []输出:[]提示:链表中节点的数目范围是 [0, 5000]-5000 <= Node.val <= 5000来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/reverse-linked-list著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
对于递归算法,最重要的就是要理解递归函数的定义。具体来说,reverseList 函数定义是这样的:
输入一个节点 head ,将以 head 为起点的链表反转,并返回反转之后的头节点。比如反转如下链表:

那么输入 reverseList(head) 后,会在这里进行递归:
ListNode* last = reverseList(head->next);
上述递归代码可以用如下图解释:

执行完这行代码之后,整个链表就会变成这样:

根据函数定义,该函数返回反转之后的头节点用变量 last 接收了。
ListNode* reverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr)
return head;
ListNode* last = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return last;
}
// 补充:迭代法
ListNode* reverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr)
return head;
ListNode* pre, *cur, *nex;
pre = nullptr;
cur = nex = head;
while (cur != nullptr) {
nex = nex->next;
cur->next = pre;
pre = cur;
cur = nex;
}
return pre;
}
02 反转链表前 N 个节点
题目要求如下:
// 将链表的前 n 个节点反转(n <= 链表长度)
ListNode* reverseN(ListNode* head, int n);
比如说对于下图链表,执行 reverseN(head, 3):

思路和反转整个链表类似,需要添加一个后驱节点接收原头节点的 next。对于反转整个链表,最后原头节点的 next 指向 nullptr。
ListNode* successor = nullptr; // 后驱节点
// 反转以 head 为起点的 n 个节点,返回新的头节点。
ListNode* reverseN(ListNode* head, int n) {
if (n == 1) {
// 记录第 n + 1 个节点
successor = head->next;
return head;
}
ListNode* last = reverseN(head->next, n - 1);
head->next->next = head;
head->next = successor;
return last;
}
03 反转链表的一部分
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]
提示:
链表中节点数目为 n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
首先,如果 left == 1,就相当于反转链表开头的前 right 个元素:
ListNode* reverseBetween(ListNode* head, int left, int right) {
if (left == 1)
return reverseN(head, right);
}
如果 m != 1 怎么办?如果我们把 head 的索引视为 1,那么我们是想从第 m 个元素开始反转对吧;如果把
head->next 的索引视为 1 呢?那么相对于 head->next,反转的区间应该是从第 m - 1 个元素开始的;那么
对于 head->next->next 呢……
ListNode* reverseBetween(ListNode* head, int left, int right) {
if (head == nullptr || head->next == nullptr)
return head;
if (left == 1) {
return reverseN(head, right);
}
head->next = reverseBetween(head->next, left - 1, right - 1);
return head;
}
