K个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析
- 需要使用到翻转链表的知识 O(n) 时间复杂度,O(1)空间复杂度
- 需要在 i d x % k = = 0 idx \% k == 0 idx%k==0 处断开链表,让前k个节点进行反转
- 不满k个的不需要翻转
- 综合下来,可以使用递归来实现(空间复杂度为O(n))和非递归版本来实现
递归版本
- 参数中需要有一个idx,用于判断当前是否需要断链和翻转
- 参数中需要有当前k个节点的head节点,用于翻转
- 当然参数中需要有当前节点指针,以便于往下递归
- 返回值就是k个一组翻转后的头节点
算法
class Solution {
// 用于翻转链表
ListNode* reverseList(ListNode* head){
if(!head || !head->next)
return head;
ListNode* new_head = head;
ListNode* next = head->next;
head->next = nullptr;
head = next;
while(head){
next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
return new_head;
}
ListNode* reverseKGroup(ListNode* current,ListNode* head,int k,int& idx){
// 递归到尾了
if(!current){
return head;
}
idx++;
// 当前节点是K的倍数,需要执行断链和翻转
if(idx%k == 0){
// next 存放下一个头节点
ListNode* next = current->next;
// 断开链表
current->next = nullptr;
auto* last = reverseKGroup(next,next,k,idx);
// 翻转当前组,获取到新表头
auto* new_head = reverseList(head);
// 翻转后,head就是尾部节点,正好接上递归回来的头节点
head->next = last;
//返回新表头
return new_head;
}else{
// 保持head不动,向下递归
return reverseKGroup(current->next,head,k,idx);
}
}
public:
ListNode* reverseKGroup(ListNode* head, int k) {
int idx = 0;
return reverseKGroup(head,head,k,idx);
}
};
非递归版本
- 需要有哨兵做新表头
- 需要在 尾部的时候判断是否是k数倍,以便翻转或者保持
算法
class Solution {
ListNode* reverseList(ListNode* head){
if(!head || !head->next)
return head;
ListNode* new_head = head;
ListNode* next = head->next;
head->next = nullptr;
head = next;
while(head){
next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
return new_head;
}
public:
ListNode* reverseKGroup(ListNode* head, int k) {
int idx = 1;
ListNode dummy(0);
// 新链表的尾部节点
ListNode* last_tail = &dummy;
// 用于遍历
ListNode* node = head;
// head节点保持当前组的头节点
while(node){
// 当前节点是K数倍
if(idx%k == 0){
ListNode* next = node->next;
// 断链
node->next = nullptr;
// 翻转
ListNode* new_head = reverseList(head);
// 连接
last_tail->next = new_head;
// 移动到新链表的尾部节点
last_tail = head;
head = next;
node = next;
}else{
node = node->next;
}
idx++;
}
last_tail->next = head;
return dummy.next;
}
};
讨论下链表翻转相关的套路模板
整个链表进行翻转
算法
// 递归
ListNode * reverseList(ListNode* head){
if(!head || !head->next)
return head;
ListNode* next = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return next;
}
// 非递归
ListNode* reverseList(ListNode* head){
if(!head || !head->next)
return head;
ListNode* new_head = head;
ListNode* next = head->next;
head->next = nullptr;
head = next;
while(head){
next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
return new_head;
}
链表前N个节点翻转
算法
// 递归
ListNode* reverseNList(ListNode*node, ListNode* head,int N){
if(!node){
return node;
}
if(N == 1){
ListNode* next = node->next;
node->next = nullptr;
ListNode* new_head = reverseList(head);
head->next = next;
return new_head;
}else{
return reverseNList(node->next,head,N-1);
}
}
ListNode* reverseNList(ListNode* head,int N){
return reverseNList(head,head,N);
}
// 非递归
ListNode* reverseNList(ListNode* head,int N){
if(!head || !head->next || N<= 1)
return head;
ListNode* new_head = head;
ListNode* next = head->next;
ListNode* tail = head;
head = next;
while(N > 1 && head){
N--;
next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
tail->next = head;
return new_head;
}
翻转链表中[m,n]的节点
算法
// 翻转整个链表
ListNode* reverseList(ListNode* head){
if(!head || !head->next) return head;
ListNode* new_head = head;
ListNode* next = head->next;
head->next = nullptr;
head = next;
while(head){
next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
return new_head;
}
// 非递归翻转前N个链表
ListNode* reverseList(ListNode* head,int N){
if(!head || !head->next || N<= 1)
return head;
ListNode* new_head = head;
ListNode* next = head->next;
ListNode* tail = head;
head = next;
while(N > 1 && head){
N--;
next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
tail->next = head;
return new_head;
}
ListNode* reverseNList(ListNode*node, ListNode* head,int N){
if(!node){
return node;
}
if(N == 1){
ListNode* next = node->next;
node->next = nullptr;
ListNode* new_head = reverseList(head);
head->next = next;
return new_head;
}else{
return reverseNList(node->next,head,N-1);
}
}
//递归翻转前N个链表
ListNode* reverseNList(ListNode* head,int N){
return reverseNList(head,head,N);
}
// 翻转[m,n]节点,其他节点保持不变
ListNode* reverseBetween(ListNode* head,int M,int N){
// 当M 为1时,就是反转前N个链表
if(M == 1)
return reverseList(head,N);
// 缩小M,前面的保持不变
head->next = reverseBetween(head->next,M-1,N-1);
return head;
}