反转链表总结
题目描述
[输入一个链表,反转链表后,输出新链表的表头。]
基础定义
#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
struct ListNode {
int val;
struct ListNode* next;
ListNode(int x) : val(x), next(nullptr){}
};
代码-递归版
ListNode* reverseListRecursion(ListNode* head) {
// base case : 只有一个头结点,反转自身
if (head->next == nullptr)
reurn head;
// 递归
ListNode* last = reverseListRecursion(head->next);
head->next->next = head;
head->next = nullptr;
return last;
}
代码-非递归
// 相当于反转结点 head 到结点 nullptr 之间的结点 [head, nullptr)
ListNode* reverseList(ListNode* head) {
if (head == nullptr)
return nullptr;
ListNode* pre = nullptr, *cur = head, *nex = head;
while(cur != nullptr) {
nex = nex->next;
cur->next = pre;
pre = cur;
cur = nex;
}
return pre;
}
拓展
反转链表的前 n 个结点
// 和反转整个链表不同的是,头结点 head 不是终端结点,所以需要记录它的后继结点。
ListNode* successor = nullpter; // 后继结点
ListNode* reverseN(ListNode* head, int n) {
// base case : n = 1 反转一个元素
if (n == 1) {
successor = head->next;
return head;
}
ListNode* last = reverseN(head->next, n - 1);
head->next->next = head;
head->next = successor;
return last;
}
反转链表的一部分
// 反转索引 [m, n] 部分的链表
ListNode* reverseBetween(ListNode* head, int m, int n) {
// base case : m = 1 ,就是反转前 n 个结点
if (m == 1)
return reverseN(head, n);
/*
将 head 的索引视为 1,是从第 m 个元素开始反转;
如果将 head->next 的索引视为 1,反转区间应该是从第 m - 1 个元素开始
*/
head->next = reverseBetween(head->next, m - 1, n - 1);
return head;
}
反转结点 a 到 结点 b 之间的结点
// 结点 [a, b) 注意和反转链表(非递归)比较:将 b 换成 nullptr 就相当于
// 反转整个链表
ListNode* reverseBetweenAB(ListNode* a, ListNode* b) {
ListNode* pre = nullptr, *cur = a, *nex = a;
while(cur != b) {
nex = nex->next;
cur->next = pre;
pre = cur;
cur = nex;
}
return pre;
}
如何 k 个一组反转链表
ListNode* reverseKGroup(ListNode* head, int k) {
if (head == nullptr)
return nullptr;
// 区间 [a, b) 包含 k 个待反转元素
ListNode* a, b;
a = b = head;
for (int i = 0; i < k; ++i) {
// 不足 K 个元素,不需要反转, base case
if (b === nullptr)
return head;
b = b->next;
}
// 反转前 k 个元素
ListNode* newHand = reverseBetweenAB(a, b);
// 递归反转后续链表并拼接
a->next = reverseKGroup(b, k);
return newHand;
}
解释下 for
循环之后的几句代码,注意reverse
函数是反转区间在[a, b)
,所以情形是这样的:
[注意] 该图片来自图中所示公众号。