给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 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]
提示:
链表中的节点数目为 n
1 <= k <= n <= 5000
0 <= Node.val <= 1000
进阶:你可以设计一个只用 O(1) 额外内存空间的算法解决此问题吗?
链表算法题重要小技巧:创建一个头节点,会使得边界条件更容易处理
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if k == 1:
return head
res = cur_first = ListNode(next=head)
counter = 0
while head:
idx = counter % k
tmp = head.next
# 新的一组第一个
if idx == 0:
# 先记录上一个的第一个元素,也就是反转后的最后一个
pre_first = cur_first
# 再记录当前组的第一个元素,也就是反转后的最后一个
cur_first = head
cur_first.next = None
# 前一个元素指针移动到本组第一个节点
pre = head
# 新的一组最后一个
elif idx == k - 1:
# 上一组第一个元素,即反转后的最后一个元素,指向当前组的最后一个元素,也就是反转后的第一个元素
pre_first.next = head
# 当前元素,也就是本组最后一个元素,指向本组前一个元素完成最后反转
head.next = pre
pre = None
# 在中间的时候
else:
# 指向前一个节点
head.next = pre
# 移动指针
pre = head
head = tmp
counter += 1
# 最后一部分反向指回来
if pre:
pre_first.next = cur_first
pre_pre = None
while pre:
tmp = pre.next
pre.next = pre_pre
pre_pre = pre
pre = tmp
return res.next
时间复杂度 O(n):一个大循环遍历一次,计 O(n),最后需要反转不需要反转的部分,计 O(n % k)。由于 k < n,则 O(n % k) < O(n / 2),O(n) + O(n % k) = O(n)
空间复杂度:常量空间。共 O(1)。