LeetCode-交换链表中节点的问题

两两交换链表中的节点

题目描述:

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
在这里插入图片描述
思路: 首先将整个链表倒置,然后再在倒置后的链表上以两个节点为单位再进行一次倒置。但是这种思路只适用与偶数个节点,如果是奇数个节点,最后一个节点倒置之后,再在倒置后的链表中以两个节点为单位进行倒置会打乱最终的顺序。所以在对链表进行操作之前,首先判断节点个数是否为奇数个。如果是奇数个,那么就将最后一个节点取下保存地址,之后操作完成后,再将该节点拼接到最终链表中。
代码:

class Solution {
	public ListNode swapPairs(ListNode head) {
        int len=0;
        ListNode cur=head,end;
        ListNode temp=new ListNode();
        //链表为空或者只有一个节点直接返回
        if(head==null) {
            return head;
        }
        if(head.next==null) {
            return head;
        }
        //遍历获得链表长度并保存最后一个节点的前一个节点地址
        while(cur.next.next!=null) {
            len++;
            cur=cur.next;
        }
        //判断节点数是否为奇数个
        if((len+2)%2!=0) {
        	//奇数个切断最后一个节点并保存地址以便之后拼接
            end=cur.next;
            cur.next=null;
        } else {
            end=null;
        }
        //倒置整个链表
        head=reverse(head);
        //记录最终链表尾巴位置方便之后拼接
        ListNode tail=head.next;
        //以两个节点为单位倒置头插
        while(head!=null) {
            ListNode hNext=head.next.next;
            ListNode headNext=head.next;
            headNext.next=temp.next;
            temp.next=head;
            head=hNext;
        }
        //拼接
        tail.next=end;
        return temp.next;

    }
	
	//链表倒置
    public ListNode reverse(ListNode head) {
        ListNode temp=new ListNode();
        while ( head != null ) {
            ListNode headNext=head.next;
            head.next=temp.next;
            temp.next=head;
            head=headNext;
        }
        return temp.next;
    }
}

K 个一组翻转链表

题目描述:

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

在这里插入图片描述
思路: 看到这题我就想到我前面的两两交换链表节点的做法。首先遍历链表记录长度,判断长度与k是否为整数倍关系,如果不是就要进行取模运算得到余数,并通过findNode函数得到倒数余数个点的地址以及倒数余数加一个点的地址,从倒数余数个点处断开链表,之后完成操作后再拼接。反转断开后的链表,并按照k个一组的方式来进行头插,在头插之前会先定义一个头节点来方便后续插入。在之后的循环中,head用来记录每一个k组的第一个元素地址,nextPre来记录每一个k组的最后一个元素的地址,Next来记录下一个k组的第一个元素的地址,nextPre和Next都通过cur接收head地址值之后遍历k-1次获取,然后头插的操作相当于再次逆置链表,只不过是以k个元素为一组的。完成外部循环后,链表拼接上之前断开的一部分即可。这种方法虽然能运行成功,但是效率比较低,代码冗长,自己钻牛角尖写出来的。

代码:

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head==null) {
            return null;
        }
        ListNode cur=head;
        int len=0;
        //得到链表长度
        while(cur!=null) {
            cur=cur.next;
            len++;
        }
        //链表长度等于k直接逆置返回
        if(len==k) {
            return reverse(head);
        }
        ListNode endPre;
        ListNode end;
        //链表长度不等于k的倍数
        if(len%k!=0) {
        	
        	//记录倒数第k+1个节点位置,方便之后断开操作
            endPre=findNode(head,len%k+1);
            //记录倒数第k个节点位置
            end=findNode(head,len%k);
            //断开后面的节点
            endPre.next=null;
            
        } else {
        //链表长度是k的倍数,则不需要断开
            end=null;
            endPre=null;
        }
        //反转剩余的链表
        head=reverse(head);
        //记录反转后头的位置,在最终链表中改位置为最后一个k组的第一个元素位置
        ListNode tail=head;
        int count=k-1;
        while(count!=0) {
        //通过遍历得到最终返回链表的最后一个k组的最后一个元素的地址
            tail=tail.next;
            count--;
        }
        ListNode temp=new ListNode(-1);
        ListNode Next=null;
        ListNode nextPre=null;
        cur=head;
        int tmp=0;
        while(head!=null) {
            tmp=k-1;
            while(tmp!=0) {
                cur=cur.next;
                tmp=tmp-1;
            }
            //通过循环得到上一个k组最后一个元素地址
            nextPre=cur;
            //这一个k组的第一个元素地址
            Next=cur.next;
            //头插操作
            nextPre.next=temp.next;
            temp.next=head;
            //更新
            head=Next;
            cur=Next;

        }
        //通过之前记录的最后一个k组的最后一个元素的地址完成拼接
        tail.next=end;
        return temp.next;
       
    }
//逆置链表
    public ListNode reverse(ListNode head) {
        ListNode temp=new ListNode(-1);
    
        while(head!=null) {
            ListNode headNext=head.next;
            head.next=temp.next;
            temp.next=head;
            head=headNext;
        }
        return temp.next;
    }

//找出倒数第k个节点
    public ListNode findNode(ListNode head,int k) {
        if(head==null) {
            return null;
        }
        ListNode fast=head;
        ListNode slow=head;
        while(k!=1) {
            fast=fast.next;
            k=k-1;
        }

        while(fast.next!=null) {
            fast=fast.next;
            slow=slow.next;
        }
        return slow;
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MinGW编译Ptyhon至pyd踩坑整理

注意需要魔法 用scoop自动安装配置MinGw 需要魔法,不需要手动配置mingw scoop install mingw安装Cython,Setuptools第三方库 关闭魔法,使用清华源 pip install setuptools -i https://pypi.tuna.tsinghua.edu.cn/simple pip install cyt…

800万纯AI战士年末大集结,硬核干货与音乐美食12月28日准时开炫

回望2023年,大语言模型或许将是科技史上最浓墨重彩的一笔。从技术、产业到生态,大语言模型在突飞猛进中加速重构万物。随着理解、生成、逻辑、记忆四大能力显著提升,大语言模型为通用人工智能带来曙光。 AI开发者们正在用算法和代码书写一个美…

Python简单网抑云数据采集 JS逆向

嗨喽,大家好呀~这里是爱看美女的茜茜呐 环境使用: Python 3.10 Pycharm 模块使用: requests -> pip install requests execjs -> pip install execjs 爬虫实现基本思路流程: 一. 数据来源分析: 明确需求: 明确采集的网站以及数据内容 网址: https://mu…

【java】java类/方法冲突解决工具

目录下查找包含特定名称(如:类名称)的Jar包 上代码: 比如要查找含有类 “org/apache/avro/Schema” 的: # 方法一 # 此方法只能查找到内容(比如:类名称)。但是不能打印jar名称 fi…

大数据Vue项目必备|Window下安装并使用nvm(含卸载node、卸载nvm、全局安装npm)

大数据Vue项目必备|Window下安装并使用nvm(含卸载node、卸载nvm、全局安装npm) 一、卸载旧版本 如果已经安装了node,那么需要先卸载node,如果没有安装那可以直接跳过这一步。 卸载:   打开控制面板 -> 打开程序和…

2个实用的快速涨粉视频号数据分析平台

很多人在做视频号的视频总不知道怎么利用视频号进行数据分析以及如何涨粉?今天就说两个视频号数据分析平台 可以查询各项爆款数据,什么账号大火、什么领域热大家都在关心什么快速了解。 1:视频号助手(https://channels.weixin.q…

一文了解什么是Selenium自动化测试?

一、Selenium是什么? 用官网的一句话来讲:Selenium automates browsers. Thats it!简单来讲,Selenium是一个用于Web应用程序自动化测试工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作浏览器一样。支持的浏…

手把手搭建腾讯云服务器教程(新手必看)

使用腾讯云服务器搭建网站全流程,包括轻量应用服务器和云服务器CVM建站教程,轻量可以使用应用镜像一键建站,云服务器CVM可以通过安装宝塔面板的方式来搭建网站,腾讯云服务器网txyfwq.com分享使用腾讯云服务器建站教程,…

社区团购行业分析:未来在门店拓展上还有很大的发展空间

社区团购是真实居住社区内居民团体的一种互联网线上线下购物消费行为,是依托真实社区的一种区域化、小众化、本地化、网络化的团购形式。简而言之,它是依托社区和团长社交关系实现生鲜商品流通的新零售模式。 社区团购,是指一定数量的消费者通…

Android 蓝牙BluetoothAdapter 相关(一)

Android 蓝牙相关 本文主要讲述android 蓝牙的简单使用. 1: 是否支持蓝牙 /*** 是否支持蓝牙** return*/ private boolean isSupportBluetooth() {BluetoothAdapter bluetoothAdapter BluetoothAdapter.getDefaultAdapter();return bluetoothAdapter ! null; }2: 开启蓝牙 …

消息队列kafka详解:Kafka架构介绍

一. 工作流程 Kafka中消息是以topic进行分类的,Producer生产消息,Consumer消费消息,都是面向topic的。 Topic是逻辑上的改变,Partition是物理上的概念,每个Partition对应着一个log文件,该log文件中存储的就…

智能优化算法应用:基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.花授粉算法4.实验参数设定5.算法结果6.参考文…

C++学习笔记(十一)------has_a和use_a关系

文章目录 前言 一、has_a关系 1.1 has_a概念 1.2 has_a中构造和析构的顺序 1.3 has_a对象的内存情况 二、use_a关系(友元关系) 1.友元函数: 2.友元类 3 使用多文件编程的方式重新编辑上述代码 总结 前言 随着技术的革新,出现各种各…

信奥赛 1310:【例2.2】车厢重组

本题解析:根据上述的要求,转化为程序的解题方案,就是用到了冒泡排序。本题中求的是旋转次数,实际上就是冒泡排序中交换的次数。 本题考察的知识点是:冒泡排序的用法。 参考代码: 上述代码仅供参考&#xff…

Vue学习计划-Vue2--VueCLi(四)组件传值和自定义事件

1. 组件传值 组件化编码流程: 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用: 一个组件在用&#xff0c…

Git 硬重置之后恢复历史提交版本

****硬重置之前一定要备份分支呀,谨慎使用硬重置,特别是很多人一起使用的分支**** 如果你在reset的时候选择了Hard选项,也就是硬重置 重置完且push过,那么被你本地和远端后面的提交记录肯定就会被抹去。 解决办法: …

TypeScript入门实战笔记 -- 01 如何快速搭建 TypeScript 学习开发环境?

🍍IDE for TypeScript 在搭建 TypeScript 环境之前,我们需要先认识几款适合 TypeScript 的 IDE。只有这样,在开发时我们才能根据实际情况选择合适的 IDE 进行安装,从而提升工作效率。 VS Code Visual Studio Code(VS C…

Win11专业版,eNSP启动失败,错误代码40 解决方法

微软Win11系统默认开启的 Virtualization-based Security (VBS)“基于虚拟化的安全性”会导致游戏、跑分性能下降。VBS 基于虚拟化的安全性,通常称为内核隔离。使用硬件虚拟化在内存中创建安全区域,为其他安全功能提供了一个安全平…

parser

"typescript-eslint/parser": "5.56.0", "vue-eslint-parser": "9.1.0", 代码来自ruoyi-plus vue-eslint-parser是一个专门用于解析Vue.js单文件组件(.vue文件)的ESLint插件。ESLint是一个用于检查和修复Java…

Python接口自动化浅析requests请求封装原理

以下主要介绍如何封装请求 还记得我们之前写的get请求、post请求么? 大家应该有体会,每个请求类型都写成单独的函数,代码复用性不强。 接下来将请求类型都封装起来,自动化用例都可以用这个封装的请求类进行请求 将常用的get、p…