链表反转,指定区间反转,k个一组反转---详解

news2024/11/28 4:27:40

牛客上的三道反转链表的题,入门题,反转链表有很多种做法,本来做第一题的时候是随便写了一种,然后后面发现我用的方法,在做第二题第三题的时候有点繁琐,所以就把三道题一起考虑了一下,选了一种相对更加清晰的思路。三道题使用同一思路解决。

反转链表

题目

反转链表-题目链接
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

思路

方法就是使用三个指针来逆转链表指向
cur指针指向当前节点,pre指向前驱,temp指向后继。
操作如图所示:
初始状态时,pre初始化为NULL
在这里插入图片描述
第一步:指针回指
在这里插入图片描述
第二步:三个指针前移
在这里插入图片描述
然后循环这两步,一直到最后即可将整个链表反转。

代码实现

时间复杂度:O(n)
空间复杂度:O(1)

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
  public:
    ListNode* ReverseList(ListNode* pHead) {
        struct ListNode* cur =pHead;
		struct ListNode* pre = NULL;
		struct ListNode* temp = cur->next;
		while(cur!=NULL){
			cur->next = pre;
			pre = cur;
			cur = temp;
			temp = temp->next;
		}
		return pre;
    }
};

链表内指定区间反转

题目

指定区间反转-题目链接

将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n),空间复杂度 O(1)。

思路

我们先找到第m个结点,然后从m到n,我们还是按照上一题的思路用三个指针将其逆置。
但是需要注意的是:我们光找到第m个结点还不够,还应该保留m的前驱结点,这样方便逆置完了之后链接回主链。
因此我们遍历的时候,用cur当作遍历指针,用pre当作前驱指针。
由于首元节点没有前驱,所以我们增加一个虚拟节点,使操作统一,不需要单独考虑首节点的特殊情况。
当我们遍历到第m个结点的时候,这时候pre保持不动,然后使用cur指针和p指针和t指针来进行逆置操作。一直逆置到第n个结点。
然后将逆置完的链表链接回主链表。
如图所示,是表长=5,m=2,n=4的情况
在这里插入图片描述
另外还需要注意一点:按照这个方法,我们最后返回head即可。但是有一种情况特殊,如果m=1,也就是说第一个开始就开始反转,那么head所指向的结点反转后就是最后一个结点了,所以不能返回head,应该返回pre->next。所以代码中这一步需要特殊处理。

代码

时间复杂度:O(n)
空间复杂度:O(1)

/**
 * struct ListNode {
 *  int val;
 *  struct ListNode *next;
 * };
 */

class Solution {
  public:
    /**
     *
     * @param head ListNode类
     * @param m int整型
     * @param n int整型
     * @return ListNode类
     */
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        // write code here
        ListNode* pre = new ListNode(-1);
        pre -> next = head;//增加一个前驱节点
        ListNode* cur = head;
        for (int i = 1; i < m; i++) {
            pre = cur;
            cur = cur->next;
        }
        ListNode* p = NULL;
        ListNode* t = cur->next;
        for (int i = m; i <= n; i++) {
            cur->next = p;//回指
            p = cur;
            cur = t;
            t = t->next;
        }
        pre->next->next = cur;//链接回主链
        pre->next = p;
        if (m == 1) head = pre->next;
        return head;
    }
};

链表中的结点每k个一组反转

题目

链表中的结点每k个一组反转-题目链接

将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。

思路

根据我们前面两题的思路,我们反转任何一段链表,只需要用到三个条件:待反转链表的第一个结点,第一个结点的前驱,反转数量。
如图,如果我们要反转这一段链表只需要知道这三个条件即可
在这里插入图片描述
代码如下,基本上就是上一题的思路:

void reverse(ListNode* pre, ListNode* cur, int k) {
        ListNode* head = pre;//把头保留下来 反转后链接的时候需要用到
        pre = NULL;//三个指针 开始反转
        ListNode* t = cur->next;
        for (int i = 1; i <= k; i++) {//限制反转数量为k
            cur->next = pre;
            pre = cur;
            cur = t;
            t = t->next;
        }
        //反转后 链接回主链
        head ->next->next = cur;
        head->next = pre;
    }

那么这个操作实现了,现在题目就简单了,每k个一组就反转,我们就遍历链表,用一个num来计数
当num=1的时候,记录下前驱pre和当前位置cur,然后当num到k的时候,说明这一段要需要反转
这一段链表的头结点以及其前驱我们都有,那就可以用这个子函数实现反转了。
假设:k=4,那么如图所示,cur指的是当前结点,已经到第四个了,cur_t和pre_t是我们保存的这一段链表的头和头的前驱
所以我们将其交给函数,反转,反转完成后,如下图所示。
这里需要注意一个点:反转前cur指向第四个结点,既然前四个反转了,那么反转之后,cur就应该指向结点1才对。
所以反转之后,我们要纠正cur的指向。(注意,只需要纠正cur的指向,不需要纠正pre,因为反转完,结点4也遍历完了,马上就指针后移了,pre直接等于纠正后的cur即可,然后cur后移即可。)
在这里插入图片描述
另外还有个问题,与上一个题目相同的问题,那就是第一组反转的链表,需要将head重置一下,不然返回head会出错。

代码

时间复杂度:O(n)
空间复杂度:O(1)
(这整个操作最坏情况下,相当于遍历了两遍链表,也就是2n,复杂度还是O(n))

/**
 * struct ListNode {
 *  int val;
 *  struct ListNode *next;
 * };
 */

class Solution {
  public:
    /**
     *
     * @param head ListNode类
     * @param k int整型
     * @return ListNode类
     */
    void reverse(ListNode* pre, ListNode* cur, int k) {
        ListNode* head = pre;
        pre = NULL;
        ListNode* t = cur->next;
        for (int i = 1; i <= k; i++) {
            cur->next = pre;
            pre = cur;
            cur = t;
            t = t->next;
        }
        //反转后 连接回主链
        head ->next->next = cur;
        head->next = pre;
    }

    ListNode* reverseKGroup(ListNode* head, int k) {
        // write code here
        ListNode* pre = new ListNode(-1);
        pre->next = head;  //增加一个新的结点
        ListNode* cur = head;
        ListNode* cur_t = NULL;//保存待反转链表的头和前驱
        ListNode* pre_t = NULL;
        int flag = 1;//标记   第一组反转时 需将head重置
        int num = 1;
        while (cur != NULL) {
            if (num == 1) {//保存待反转链表的头和前驱
                cur_t = cur;
                pre_t = pre;
            }
            if (num % k == 0) {
                if (flag) { //第一次反转
                    head = cur;
                    flag = 0;
                }
                reverse(pre_t, cur_t, k);
                //反转完成后 纠正cur指针位置
                cur = cur_t;
                num = 0;//计数置0
            }
            pre = cur;
            cur = cur->next;
            num++;
        }
        return head;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/88348.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Python计算机毕业设计二手图书回收销售网站Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

python3.9.0 windows环境搭建

第一步&#xff1a; 下载安装包&#xff1a;CNPM Binaries Mirror 执行exe安装。。。。。 第二步&#xff1a;升级pip 和 setuptools&#xff08;避免在每一个虚拟环境中都要升级&#xff09; python -m pip install --upgrade pip python -m pip install --upgrade setuptoo…

基于android音乐播放器的设计

本科毕业论文&#xff08;设计&#xff09;诚信声明 本人郑重声明&#xff1a;所呈交的毕业论文&#xff08;设计&#xff09;&#xff0c;题目《………基于android音乐播放器的设计……………………………》是本人在指导教师的指导下&#xff0c;进行研究工作所取得的成果。对…

ChatGPT写Flask-Demo——有体验地址

ChatGPT中API的试用 最近ChatGPT智能AI很火&#xff0c;可以写代码&#xff0c;DEBUG&#xff0c;写简历等等 上去查看了一下&#xff0c;是可以调用API的&#xff0c;本着学习的态度就是用这个款AI辅助我写了一个demo&#xff08;本人原来对flask只懂一点点&#xff09; 目录0…

基于51单片机的数字电压表(ADC0832)(Proteus仿真+程序)

编号&#xff1a;29 基于51单片机的数字电压表&#xff08;ADC0832&#xff09; 功能描述&#xff1a; 本设计由51单片机最小系统ADC0832模块两路模拟量输入模块液晶1602显示模块 1、主控制器是AT89C82单片机 2、ADC0832模数转换器进行A/D转换&#xff0c;读取电压两路数据&a…

栅格瓦片和矢量瓦片

地图瓦片 地图瓦片的诞生 在以前没有瓦片的概念时&#xff0c;由于地图要素多、范围大等特点导致地图数据量很大&#xff0c;如果从浏览器可视化地图就对网络和数据渲染能力有高的要求&#xff0c;所以导致瓦片诞生以前&#xff0c;地图多在pc电脑中桌面软件使用。随着互联网…

【YOLOv5】LabVIEW+YOLOv5快速实现实时物体识别(Object Detection)

前言 前面我们给大家介绍了基于LabVIEWYOLOv3/YOLOv4的物体识别&#xff08;对象检测&#xff09;&#xff0c;今天接着上次的内容再来看看YOLOv5。本次主要是和大家分享使用LabVIEW快速实现yolov5的物体识别&#xff0c;本博客中使用的智能工具包可到主页置顶博客LabVIEW AI视…

一个简单的MATLAB脚本——快速行进算法(FMM))

一个简单的MATLAB脚本——快速行进算法&#xff08;FMM&#xff09; 介绍快速行进算法&#xff08;FMM&#xff09;的简单MATLAB脚本&#xff0c;不到20行代码实现快速行进算法的运算结果&#xff0c;而且计算速度非常快。给了两个实例模型来说明计算结果。 文章目录一个简单的…

unicloud生成微信小程序分享码

一&#xff0c;方案 看了官方的文档&#xff0c;获取小程序码有三种&#xff0c;我采用的是第二种&#xff1a;生成数量不受限制的分享码。 对应的官方文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/qr-code/getUnlimitedQRCode.…

MySQL 锁

在之前的文章有多次提到&#xff0c;MySQL在数据更新和性能优化上会用到锁机制。我们在实际的应用中也经常会遇到锁相关的问题&#xff0c;即使很多时候我们并没有人为的为数据库添加锁&#xff0c;但还是会出现死锁的问题&#xff0c;这是因为在我们操作数据时MySQL隐式的帮我…

java UDP通信程序DatagramSocket数据发送

首先 我们先来了解一下 UDP 首先 他是一种不可靠的网络协议 他在通信的两端 各建立一个 Socke对象 但是他们只是 发送和接收数据的对象 发送端只管发送 不会顾及接收端是否接到 接收到只负责接收数据 而不会给出发送端反馈 因此对于UDP通信的双方而言 是有没什么 客户端和服务…

架构师进阶,微服务设计与治理的 16 条常用原则

今天将从存储的上一层「服务维度」学习架构师的第二项常用能力 —— 微服务设计与治理。 如何设计合理的微服务架构&#xff1f; 如何保持微服务健康运行&#xff1f; 这是我们对微服务进行架构设计过程中非常关注的两个问题。 本文对微服务的生命周期定义了七个阶段&#xf…

正大国际期货:为什么外盘期货顺势交易这么难

要回答“为什么趋势交易这么难&#xff1f;”需要先回答&#xff1a;“为什么交易&#xff1f;”。 你应该为了抓住赚取期望利润的机会而交易&#xff0c;为了长期持续赚钱的目的而交易&#xff0c;而不是为了赚得短期利润的喜悦而交易&#xff0c;也不是为了证明你的市场分析…

音频转文字怎么转?这些方法值得一试

在日常生活中我们经常会遇到要把音频转换成文字的情况&#xff0c;很多小伙伴还在使用传统的方法&#xff0c;一边播放一边记录。虽然这样能解决问题&#xff0c;但是需要花费很多时间&#xff0c;效率特别低。我们不妨尝试使用一些转换软件&#xff0c;这样就能节省很多时间了…

界面组件Kendo UI for Angular——让应用数据显示更直观!(二)

Kendo UI致力于新的开发&#xff0c;来满足不断变化的需求&#xff0c;通过React框架的Kendo UI JavaScript封装来支持React Javascript框架。Kendo UI for Angular是专用于Angular开发的专业级Angular组件&#xff0c;telerik致力于提供纯粹的高性能Angular UI组件&#xff0c…

Word处理控件Aspose.Words功能演示:在 Java 中将 Word DOCX 转换为 Markdown

如今&#xff0c;Markdown ( MD ) 格式被广泛用于编写在线文章、博客和文档。但是&#xff0c;在大型文档的情况下&#xff0c;它的语法变得难以记忆和书写。为方便起见&#xff0c;您可以在 MS Word 中编写内容&#xff0c;然后将DOCX文件转换为 Markdown。为了以编程方式执行…

nacos--基础--5.2.2--集成--SpringCloud--服务注册,发现,负载均衡

nacos–基础–5.2.2–集成–SpringCloud–服务注册&#xff0c;发现&#xff0c;负载均衡 代码位置 https://gitee.com/DanShenGuiZu/learnDemo/tree/master/nacos-learn1、介绍 服务发现客户端 从服务发现中心获取服务列表服务消费 通过负载均衡获取服务地址 2、添加依赖 …

jdk安装配置教程2022年12月最新版

这两天配了好几遍jdk&#xff0c;删了又下下了又删&#xff0c;总结一下&#xff0c;也算有点收获 1. 下载&#xff1a;官网Java Downloads | Oracle jdk1.8在下面&#xff0c;上面是最新的jdk17和jdk19 2.下载完成后&#xff0c;一路安装解压&#xff08;我撞在了C盘&#…

IfcOpenShell简明教程【BIM】

IFC 是用于存储 BIM 数据的 ISO 标准格式。 IfcOpenShell 是一个包含 Python 库的项目&#xff0c;可以用来解析 IFC 文件。 1、下载安装IfcOpenShell 首先&#xff0c;我们需要下载并安装 IfcOpenShell python。 目前没有 IfcOpenShell 的 API 文档&#xff0c;但考虑到它主…

Vector源码解析

Vector源码解析 简介 Vector 是一个古老的 线程安全(内部的核心方法都加了synchronized) 的容器&#xff0c;在 JDK1.0 时就已经存在&#xff0c;到如今已经很少使用。 基本结构与 ArrayList 类似&#xff0c;可以认为是线程安全版本的 ArrayList&#xff0c;但因为 Vector …