给你链表的头节点 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 <= 50000 <= Node.val <= 1000
解题思路
-
**哨兵节点(dummy):**用一个哨兵节点作为链表的虚拟头,避免单独处理头节点翻转的边界情况,简化代码逻辑。
-
分组定位: 每次从当前
prev节点出发,向后遍历 k 个节点,定位到当前组的尾节点end。如果遍历不足 k 个节点,说明已经到链表末尾,直接返回结果。 -
子链表翻转: 调用辅助函数
reverse翻转当前组的子链表(从prev.next到end),该函数通过迭代方式完成单链表翻转,时间复杂度为 O (k)。 -
组间连接: 翻转后,将当前组的新头节点连接到
prev之后,再将当前组的原头节点(翻转后的尾节点)连接到下一组的头节点,完成整个组的衔接。 -
迭代推进: 更新
prev为当前组的原头节点(翻转后的尾节点),进入下一轮循环,处理后续节点。
复杂度分析
- 时间复杂度:O (n),其中 n 是链表的节点数。每个节点会被访问两次(一次定位分组,一次翻转),整体复杂度为线性。
- 空间复杂度:O (1),仅使用了常量级的额外空间,属于原地操作。
Python代码
python
from typing import Optional
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]:
# 哨兵节点,简化头节点处理
dummy = ListNode(0)
dummy.next = head
prev = dummy
while True:
# 1. 检查剩余节点是否有k个
end = prev
for _ in range(k):
end = end.next
if not end:
return dummy.next
# 2. 保存当前组的下一组头节点
next_group_head = end.next
# 3. 断开当前组与后续节点的连接
end.next = None
current_group_head = prev.next
# 4. 翻转当前组
prev.next = self.reverse(current_group_head)
# 5. 连接翻转后的组与下一组
current_group_head.next = next_group_head
# 6. 更新prev为当前组的原头节点(翻转后的尾节点)
prev = current_group_head
# 辅助函数:翻转单链表,返回新的头节点
def reverse(self, head: ListNode) -> ListNode:
prev = None
curr = head
while curr:
next_node = curr.next # 暂存下一个节点
curr.next = prev # 翻转当前节点的指针
prev = curr # prev指针后移
curr = next_node # curr指针后移
return prev
# 辅助函数:将列表转为链表
def list_to_linkedlist(arr):
dummy = ListNode(0)
curr = dummy
for num in arr:
curr.next = ListNode(num)
curr = curr.next
return dummy.next
# 辅助函数:将链表转回列表(便于打印查看结果)
def linkedlist_to_list(head):
res = []
curr = head
while curr:
res.append(curr.val)
curr = curr.next
return res
# 测试代码
if __name__ == "__main__":
# 测试案例1:输入[1,2,3,4,5],k=2,预期输出[2,1,4,3,5]
head1 = list_to_linkedlist([1, 2, 3, 4, 5])
sol = Solution()
reversed_head1 = sol.reverseKGroup(head1, 2)
print("测试案例1结果:", linkedlist_to_list(reversed_head1)) # 输出 [2,1,4,3,5]
# 测试案例2:输入[1,2,3,4,5],k=3,预期输出[3,2,1,4,5]
head2 = list_to_linkedlist([1, 2, 3, 4, 5])
reversed_head2 = sol.reverseKGroup(head2, 3)
print("测试案例2结果:", linkedlist_to_list(reversed_head2)) # 输出 [3,2,1,4,5]
# 测试案例3:输入[1],k=1,预期输出[1]
head3 = list_to_linkedlist([1])
reversed_head3 = sol.reverseKGroup(head3, 1)
print("测试案例3结果:", linkedlist_to_list(reversed_head3)) # 输出 [1]
LeetCode提交代码
python
# 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]:
# 哨兵节点,简化头节点处理
dummy = ListNode(0)
dummy.next = head
prev = dummy
while True:
# 1. 检查剩余节点是否有k个
end = prev
for _ in range(k):
end = end.next
if not end:
return dummy.next
# 2. 保存当前组的下一组头节点
next_group_head = end.next
# 3. 断开当前组与后续节点的连接
end.next = None
current_group_head = prev.next
# 4. 翻转当前组
prev.next = self.reverse(current_group_head)
# 5. 连接翻转后的组与下一组
current_group_head.next = next_group_head
# 6. 更新prev为当前组的原头节点(翻转后的尾节点)
prev = current_group_head
# 辅助函数:翻转单链表,返回新的头节点
def reverse(self, head: ListNode) -> ListNode:
prev = None
curr = head
while curr:
next_node = curr.next
curr.next = prev
prev = curr
curr = next_node
return prev
程序运行截图展示

总结
题目要求将链表每k个节点一组进行翻转,不足k个的保持原序。使用哨兵节点简化处理,通过分组定位、子链表翻转和组间连接实现。时间复杂度O(n),空间复杂度O(1)。Python代码通过迭代翻转每组链表,并处理边界条件,测试案例验证了正确性。例如,输入[1,2,3,4,5]和k=2时输出[2,1,4,3,5]。该方法高效且符合原地操作要求。