算法题: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
思路
将整个链表不断切成长度为k的小链,将小链翻转后再拼接起来,需要实现cut函数和reverse函数
代码
C++
/**
* Definition for singly-linked list.
* 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) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (head == nullptr || head->next == nullptr) return head;
ListNode* p = head;
vector<pair<ListNode*, ListNode*>> list;
while (true) {
auto cut_res = cut(p, k);
if (!cut_res.first) {
list.push_back({p, nullptr});
break;
}
ListNode* rev = reverse(p);
list.push_back({rev, p});
p = cut_res.second;
}
for (int i = 0;i < list.size()-1;i++) { // 拼接
list[i].second->next = list[i+1].first;
}
return list[0].first;
}
ListNode* reverse(ListNode* head) {
if (!head || !head->next) return head;
ListNode* p = nullptr;
ListNode* cur = head;
while (cur) {
ListNode* nxt = cur->next;
cur->next = p;
p = cur;
cur = nxt;
}
return p;
}
pair<ListNode*, ListNode*> cut(ListNode* head, int k) {
ListNode* p = head;
while (--k) {
if (p) p = p->next;
else break;
}
ListNode* q = nullptr;
if (p) {
q = p->next;
p->next = nullptr;
}
return {p, q}; // 分别返回切段后的前一段末尾和后一段开头
}
};
时间复杂度:O(N)
空间复杂度:O(N)