题目描述:
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
进阶:
1、你可以设计一个只使用常数额外空间的算法来解决此问题吗?
2、你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例:
示例1:
示例2:
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
示例 3:
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]
示例 4:
输入:head = [1], k = 1
输出:[1]
解析:
将一链表以每长度为k进行子链表的翻转,总步骤可概括为:
1. 分组,记得注意在最后一组链表的情况,不足k不需要翻转。
2. 对组内元素的翻转。
3. 拼接子链表。
先说一下对子链的翻转的方法:
方法一:迭代与递归
迭代代码:
ListNode* reverseList(ListNode* head)
{
ListNode node,*ptr=&node,*temp;
//当当前节点不为空节点时
while (head)
{
//先键一个指针存储当前节点
temp = head;
head = head->next;
temp->next = ptr->next;
ptr->next = temp;
}
return ptr->next;
}
递归代码:
ListNode* reverseList(ListNode* head)
{
if(head==nullptr||head->next==nullptr)
{
return head;
}
ListNode* new_node = reverseList(head->next);
//关键:
//以原先链表为基准,目前的链表结构是:
//未翻转的链表部分-> head ->已经翻转的链表部分的末尾(这前半部分依旧保持原先顺序)<-已经翻转的链表的剩余部分
//此刻,head节点与 原先链表的后继节点 形成环
head->next->next = head;
//断开环,使head成为翻转链表的末尾
head->next = nullptr;
return new_node;
}
方法二:利用栈
ListNode* reverseList(ListNode* head)
{
if(head==nullptr||head->next==nullptr)
{
return head;
}
ListNode dummyHead, * ptr = &dummyHead;
stack<ListNode*> my_stack;
while (head)
{
my_stack.push(head);
head = head->next;
}
while (!my_stack.empty())
{
ListNode* temp = my_stack.top();
my_stack.pop();
ptr->next = temp;
ptr = ptr->next;
}
//最后一定要记得把原链表的首节点后继指向nullptr,因为此刻它依然还是指向第二个元素
ptr->next = nullptr;
return dummyHead.next;
}
其次是拼接问题,在子链翻转的过程中判断跳出循环的是否到达了空指针,因此我们这里也可以给函数多加一位参数,另设一个指针表示子链的末端。
代码:
class Solution {
public:
pair<ListNode*,ListNode*> reverseList(ListNode *head,ListNode *end_node)
{
ListNode dummy_head, * ptr = &dummy_head;
//原子链的首节点必为返回的尾节点
ListNode* return_end = head;
//模拟子链末端的空指针
ListNode* dummy_end = end_node->next;
while (head != dummy_end)
{
ListNode* temp = head;
head = head->next;
temp->next = ptr->next;
ptr->next = temp;
}
//返回的是翻转链表的首节点和末节点
return { dummy_head.next,return_end };
}
ListNode* reverseKGroup(ListNode* head, int k)
{
ListNode* dummy_head = new ListNode(0, head);
//子链首节点的前序节点
ListNode* start_node = dummy_head;
while (head)
{
//记录翻转前子链的末端
ListNode* end_node = start_node;
//计算子链长度
for(int i=0;i<k;i++)
{
end_node = end_node->next;
//长度不足K表示这是最后一段子链,则可以返回链表了
if(!end_node)
{
return dummy_head->next;
}
}
//记录翻转子链的后继节点
ListNode* next_node = end_node->next;
pair<ListNode*, ListNode*> result = reverseList(head, end_node);
head = result.first;
end_node = result.second;
//连接子链
start_node->next = head;
end_node->next = next_node;
//更新节点
start_node = end_node;
head = start_node->next;
}
return dummy_head->next;
}
};