题目
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
说明:
(1)k 是一个正整数,它的值小于或等于链表的长度。
(2)如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例如下所示:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
解决思路
- 方法:循环调用“基于递归法反转单链表”解决此题,递归法反转单链表请参考此博文的思路2:参考这里
- 步骤:
说明:
- 指针p始终指向待反转部分的上一个节点。
- 反转前指针q指向待反转部分的第一个节点,反转后指针q指向反转部分的尾结点。
- 改变指针的指向后,指针p指向下一次要被反转部分的第一个节点的上一个节点,指针q指向下一次要被反转部分的第一个节点。
代码
- C++代码:
# include <stdio.h>
struct ListNode {
int val;
ListNode *next;
ListNode(): val(0), next(nullptr) {}
ListNode(int val): val(val), next(nullptr) {}
ListNode(int val, ListNode *next): val(val), next(next) {}
};
class Solution {
public:
// 真正进行链表反转的操作(递归法反转单链表)
ListNode *trueReverseN(ListNode *head, int num) {
if (nullptr == head || nullptr == head->next || 1 == num) {
return head;
}
ListNode *cur = head->next;
ListNode *pre = trueReverseN(cur, num - 1); // 指向反转后链表的头结点
head->next = cur->next;
cur->next = head;
cur = cur->next;
return pre;
}
// 先判断链表的长度够不够n个节点,如果够再进行反转。
ListNode *reverseN(ListNode *head, int n) {
if (nullptr == head || nullptr == head->next || 1 == n) {
return head;
}
int cnt = n;
ListNode *p = head;
while (--n && p) { // 判断链表的长度够不够n个节点。
p = p->next;
}
if (nullptr == p) { // 说明不够n个节点
return head;
}
// 当链表节点够n个节点时,才进行真正的反转链表的操作。
return trueReverseN(head, cnt);
}
ListNode *reverseKGropu(ListNode *head, int k) {
if (nullptr == head || nullptr == head->next || 1 == k) {
return head;
}
ListNode ret(0, head); // 虚拟头节点
ListNode *p = &ret; // 初始时刻将指针p指向虚拟头节点,p节点的下一个节点即要进行反转部分链表的第一个节点
ListNode *q = p->next; // 初始时刻q指针指向要进行反转部分链表的第一个节点,反转后q指针指向反转部分链表的尾结点。
// (p->next = reverseN(q, k)) != q:如果反转后返回的节点不为q节点,则说明反转成功。
// 循环调用“递归法反转链表”
while ((p->next = reverseN(q, k)) != q) {
p = q;
q = q->next;
}
return ret.next;
}
};
int main() {
ListNode *a = new ListNode(1);
ListNode *b = new ListNode(2);
ListNode *c = new ListNode(3);
ListNode *d = new ListNode(4);
ListNode *e = new ListNode(5);
a->next = b;
b->next = c;
c->next = d;
d->next = e;
ListNode *head = a;
printf("before reverse: ");
while (head) {
printf("%d ", head->val);
head = head->next;
}
printf("\n");
head = a;
int k = 2;
Solution *solution = new Solution();
ListNode *ret = solution->reverseKGropu(head, 2);
printf("after reverse: ");
while (ret) {
printf("%d ", ret->val);
ret = ret->next;
}
return 0;
}
- python代码
# -*- coding: utf-8 -*-
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def trueReverseN(self, head: ListNode, n: int) -> ListNode:
if not head or not head.next or 1 == n:
return head
cur: ListNode = head.next
pre: ListNode = self.trueReverseN(cur, n - 1)
head.next = cur.next
cur.next = head
cur = cur.next
return pre
def reverseN(self, head: ListNode, num: int) -> ListNode:
if not head or not head.next or 1 == num:
return head
cnt: int = num
p: ListNode = head
while num > 1 and p:
p = p.next
num -= 1
if not p:
return head
return self.trueReverseN(head, cnt)
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next or 1 == k:
return head
ret = ListNode(0, head)
p = ret
q = p.next
while True:
p.next = self.reverseN(q, k) # 注意是传入q节点,而不是head
if p.next != q:
p = q
q = q.next
else:
break
return ret.next
def main():
a: ListNode = ListNode(1)
b: ListNode = ListNode(2)
c: ListNode = ListNode(3)
d: ListNode = ListNode(4)
e: ListNode = ListNode(5)
a.next = b
b.next = c
c.next = d
d.next = e
head: ListNode = a
print('before reverse: ', end='')
while head:
print(head.val, end=' ')
head = head.next
print()
head = a
solution = Solution()
ret = solution.reverseKGroup(head, 2)
print("after reverse: ", end='')
while ret:
print(ret.val, end=' ')
ret = ret.next
if __name__ == "__main__":
main()
说明
- 对应LeetCode第25题。
- 链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/