8.5 链表专题:LeetCode 25. K个一组翻转链表

高效解决K个一组翻转链表的算法详解

1. 题目链接

LeetCode 25. K个一组翻转链表

2. 题目描述

给定一个链表和一个正整数k,要求每k个节点为一组进行翻转,剩余不足k的节点保持原有顺序。例如:

  • 输入:1 → 2 → 3 → 4 → 5k=2
  • 输出:2 → 1 → 4 → 3 → 5

3. 示例分析

假设输入链表为1 → 2 → 3 → 4 → 5k=3

  1. 前3个节点1→2→3翻转得到3→2→1
  2. 后2个节点4→5不足k,保持原顺序
  3. 最终结果:3 → 2 → 1 → 4 → 5

可视化翻转过程

初始状态:dummy → |1 → 2 → 3| → 4 → 5
第一次翻转:dummy → 3 → 2 → 1 → |4 → 5|

4. 算法思路

分组头插法(时间复杂度O(n))

核心思想:将链表划分为多个k节点长度的子链表,利用头插法实现原地翻转。

具体步骤

  1. 计算翻转次数:遍历链表获取总长度,计算需要翻转的组数n = 总长度 / k
  2. 分组翻转
    • 使用哑节点dummy简化头节点处理
    • 每次处理k个节点,通过头插法实现子链表翻转
  3. 连接剩余节点:处理完所有完整组后,直接连接剩余节点

5. 边界条件与注意事项

  • k=1的特殊情况:直接返回原链表
  • 链表长度不足k:无需翻转,直接返回
  • 内存管理:正确释放哑节点内存
  • 指针操作顺序:注意维护prevcur的位置关系
  • 循环终止条件:外层循环次数严格等于组数n

6. 代码实现

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        // 计算链表总长度
        int total = 0;
        ListNode* cur = head;
        while(cur) {
            total++;
            cur = cur->next;
        }
        int groups = total / k; // 完整翻转的组数
        
        // 创建哑节点简化操作
        ListNode* dummy = new ListNode(0);
        ListNode* prev = dummy;
        cur = head;
        
        // 分组翻转
        for(int i = 0; i < groups; i++) {
            ListNode* groupHead = cur; // 记录当前组的原始头节点
            for(int j = 0; j < k; j++) {
                ListNode* next = cur->next;  // 保存下一个节点
                cur->next = prev->next;      // 头插法核心操作
                prev->next = cur;            // 更新前驱节点的next
                cur = next;                  // 移动当前指针
            }
            prev = groupHead; // 前驱指针移动到当前组的末尾
        }
        
        // 连接剩余节点
        prev->next = cur;
        
        // 释放哑节点内存
        ListNode* res = dummy->next;
        delete dummy;
        return res;
    }
};

代码解析

  1. 哑节点技巧dummy->next始终指向结果链表的头部,避免处理头节点的特殊情况
  2. 头插法实现细节
    • cur->next = prev->next:将当前节点插入到前驱节点之后
    • prev->next = cur:更新前驱节点的next指针
    • 循环k次完成一组节点的翻转
  3. 指针移动逻辑
    • prev指针在每组翻转后移动到该组的原始头节点位置(即翻转后的末尾节点)
    • cur指针始终指向待处理的下一个节点

复杂度分析

  • 时间复杂度:O(n)
    • 计算长度需要O(n)
    • 每个节点被处理两次(插入和连接),总体时间复杂度保持线性
  • 空间复杂度:O(1)
    • 仅使用常数级别的额外空间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值