【LeetCode刷题】K 个一组翻转链表

给你链表的头节点 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

解题思路

  1. **哨兵节点(dummy):**用一个哨兵节点作为链表的虚拟头,避免单独处理头节点翻转的边界情况,简化代码逻辑。

  2. 分组定位: 每次从当前prev节点出发,向后遍历 k 个节点,定位到当前组的尾节点end。如果遍历不足 k 个节点,说明已经到链表末尾,直接返回结果。

  3. 子链表翻转: 调用辅助函数reverse翻转当前组的子链表(从prev.nextend),该函数通过迭代方式完成单链表翻转,时间复杂度为 O (k)。

  4. 组间连接: 翻转后,将当前组的新头节点连接到prev之后,再将当前组的原头节点(翻转后的尾节点)连接到下一组的头节点,完成整个组的衔接。

  5. 迭代推进: 更新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]。该方法高效且符合原地操作要求。

相关推荐
测试摆渡媛2 小时前
Excel模板填充工具(工具&脚本分享)
python·数据挖掘·pandas
夔曦2 小时前
【python】月报考勤工时计算
开发语言·python
fl1768312 小时前
基于python实现PDF批量加水印工具
开发语言·python·pdf
i02082 小时前
Prompt
python
Freed&2 小时前
用 Python 写一个“会下小纸条雨”的暖心程序 —— Flask 网页版 + Tkinter 桌面版
python
_codemonster2 小时前
手语识别及翻译项目实战系列(五)整体架构代码详细代码实现
人工智能·python·计算机视觉·架构
Eugene__Chen2 小时前
Java的SPI机制(曼波版)
java·开发语言·python
程序猿20232 小时前
JVM与JAVA
java·jvm·python
独隅2 小时前
本地大模型训练与 API 服务部署全栈方案:基于 Ubuntu 22.04 LTS 的端到端实现指南
服务器·python·语言模型