当前位置: 首页 > article >正文

LeetCode25:K个一组翻转链表

原题地址:. - 力扣(LeetCode)

题目描述

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

实现思路

  • 定义节点:使用ListNode类表示链表节点。

  • 设置虚拟头节点:使用一个虚拟头节点(hair)来处理链表的头部,使得处理操作更加简洁。

  • 遍历链表:使用一个指针head从链表头部开始遍历,找到每一组k个节点:

    • 通过一个循环检查剩余的节点是否至少有k个。
    • 如果不足k个,返回结果(即未变更的链表部分)。
  • 反转k个节点:使用myReverse方法反转找到的k个节点:

    • 该方法接收头节点和尾节点,并逐步将节点的指向反转,最终返回新的头和尾。
  • 重新链接链表:将反转后的子链表连接回原链表:

    • 更新pre.next指向反转后的头节点。
    • 更新反转后的尾节点指向接下来的节点。
  • 更新指针:继续循环,更新prehead以处理下一个k个节点。

源码实现

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        // 创建一个虚拟头节点,简化边界处理
        ListNode hair = new ListNode(0);
        hair.next = head; // 虚拟节点指向原链表的头
        ListNode pre = hair; // 用于连接反转后的链表

        // 遍历链表
        while (head != null) {
            ListNode tail = pre; // 每次从pre开始

            // 检查剩余部分长度是否大于等于 k
            for (int i = 0; i < k; ++i) {
                tail = tail.next; // 移动tail指针
                if (tail == null) {
                    return hair.next; // 如果不足k个,直接返回
                }
            }

            ListNode nex = tail.next; // 记录下一部分的起始节点
            // 反转k个节点
            ListNode[] reverse = myReverse(head, tail);
            head = reverse[0]; // 新的头节点
            tail = reverse[1]; // 新的尾节点

            // 将反转后的子链表接回原链表
            pre.next = head; // pre指向新的头节点
            tail.next = nex; // 新尾节点指向下一部分的起始节点
            pre = tail; // 更新pre
            head = tail.next; // 更新head指向下一组
        }

        return hair.next; // 返回新链表的头
    }

    // 反转链表的方法,返回新的头和尾
    public ListNode[] myReverse(ListNode head, ListNode tail) {
        ListNode prev = tail.next; // prev指向tail的下一个
        ListNode p = head; // p用于遍历反转

        // 逐步反转节点
        while (prev != tail) {
            ListNode nex = p.next; // 记录下一个节点
            p.next = prev; // 反转当前节点
            prev = p; // prev移动到当前节点
            p = nex; // p移动到下一个节点
        }

        return new ListNode[]{tail, head}; // 返回新的尾和头
    }
}

复杂度分析

  • 时间复杂度:O(n),其中n是链表的节点数。每个节点最多被访问两次,所以整体时间复杂度是线性的。
  • 空间复杂度:O(1)。我们只使用了常数的额外空间,主要是指针,不需要额外的存储结构。因此空间复杂度为常数

http://www.kler.cn/a/379504.html

相关文章:

  • MQTT自动发送消息工具(自动化测试MQTT)
  • 小张求职记四
  • RestTemplate 常用方法(提供了多种方法来发送 HTTP 请求)
  • mysql查表相关练习
  • keepalive+mysql8双主
  • GPT-Sovits-2-微调模型
  • LeetCode 19. 删除链表的倒数第 N 个结点(java)
  • Java Iterator 实现杨辉三角
  • Redis 补充概念
  • Unity 6 基础教程(Unity 界面)
  • 百度搜索引擎的工作原理
  • javaScript-----一维数组和数组对象去重的多种方法
  • 使用 MySQL Workbench 创建和管理用户
  • 手册更新 | RK3568开发板Openwrt文件系统构建
  • ClkLog企业版(CDP)预售开启,更有鸿蒙SDK前来助力
  • Win/Linux/Kylin 系统安装指定版本 jdk(8u171为例)
  • 学习记录:js算法(八十四):子集 II
  • vue系列==vue组件
  • sparkSQL面试题
  • Go语言sync.WaitGroup与errgroup.Group用法详解
  • 迅为itop-3568开发板AMP双系统使用手册之烧写AMP镜像
  • 力扣第33题:搜索旋转排序数组
  • 聚水潭数据集成到MySQL的技术实操与解决方案
  • Vue前端开发:事件对象参数
  • Docker-安装
  • Flutter UI架构(3)