【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]。该方法高效且符合原地操作要求。

相关推荐
m0_613856294 小时前
mysql如何利用事务隔离级别解决特定业务冲突_mysql隔离方案选型
jvm·数据库·python
昵称小白5 小时前
复杂度分析方法
算法
我的xiaodoujiao5 小时前
API 接口自动化测试详细图文教程学习系列16--项目实战演练3
python·学习·测试工具·pytest
科研前沿5 小时前
2026 数字孪生前沿科技:全景迭代报告 —— 镜像视界生成式孪生(Generative DT)技术白皮书
大数据·人工智能·科技·算法·音视频·空间计算
ID_180079054735 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
时空系6 小时前
第10篇:继承扩展——面向对象编程进阶 python中文编程
开发语言·python·ai编程
CHANG_THE_WORLD7 小时前
python 批量终止进程exe
开发语言·python
liann1197 小时前
3.2_红队攻击框架--MITRE ATT&CK‌
python·网络协议·安全·网络安全·系统安全·信息与通信
云天AI实战派7 小时前
AI 智能体问题排查指南:ChatGPT、API 调用到 Agent 上线失灵的全流程修复手册
大数据·人工智能·python·chatgpt·aigc
学涯乐码堂主7 小时前
有趣的“打擂台算法”
c++·算法·青少年编程·gesp