25. K 个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:
1->2->3->4->5
当 k = 2 时,应当返回:
2->1->4->3->5
当 k = 3 时,应当返回:
3->2->1->4->5
说明:
- 你的算法只能使用常数的额外空间。
- 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
解法一:
// 时间复杂度O(n), 空间复杂度O(n).
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
// 返回新链表头
ListNode* reverse(ListNode* start, ListNode* end, int k) {
ListNode *pre = end, *cur = start, *next;
while (k-- > 0) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
ListNode* reverseKGroup(ListNode* head, int k) {
if (!head) return nullptr;
ListNode* p = head;
int c = k;
while (c > 0 && p) {
p = p->next;
--c;
}
if (c > 0) return head;
ListNode* nextHead = reverseKGroup(p, k);
return reverse(head, nextHead, k);
}
};
解法二:
// 时间复杂度O(n), 空间复杂度O(1)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverse(ListNode* start, ListNode* end, int k) {
ListNode *pre = end, *cur = start, *next;
while (k-- > 0) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
ListNode* findNextHead(ListNode* head, int k) {
ListNode* p = head;
while (k > 1 && p) {
p = p->next;
k--;
}
if (!p) return head;
return p;
}
ListNode* reverseKGroup(ListNode* head, int k) {
if (k == 1) return head;
ListNode* cur = head;
ListNode* newList = head;
bool first = true;
while (true) {
ListNode* p = cur;
int c = k;
while (c > 0 && p) {
p = p->next;
--c;
}
if (c > 0) break;
ListNode* end = findNextHead(p, k);
if (first) {
newList = reverse(cur, end, k);
first = false;
} else reverse(cur, end, k);
if (end == p) break;
cur = p;
}
return newList;
}
};
解法一: 递归法。如果采用从前向后反转的方式,在当前组反转完成后还不知道下一组的起始结点,为了避免这种问题,以递归方式从右向左按组反转。
解法二: 迭代法。每次先找到下一组(反转后的)头结点,将当前组所转,进入下一组进行同样的操作。直到组内元素少于K。
2019/09/21 12:47