算法4: LeetCode_K个节点的组内逆序调整
创始人
2024-02-10 21:01:27
0
  • 最近一直都是链表的算法练习,今天刷的是LeetCode原题,还是关于链表的节点逆转,难度等级:Hard.
  • 首先看题目:给定一个单聊表的头节点head和一个正整数k, 要求实现k个节点的小组内部逆序,如果最后一组不够k个就不调整。 如果给定的链表为1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8,k = 3,调整完以后链表变成 3 -> 2 -> 1 -> 6 -> 5 -> 4 -> 7 -> 8
  • 解题思路:
  1. 既然是给定长度的组内局部逆转,首先肯定是要对链表进行分组,符合条件的小组内部进行链表的逆转。不符合条件的小组,则保持不变
  2. 如果符合条件,每个小组的内部其实都设计到头节点和尾结点的对调,并且前一个小组的尾结点需要持有下一小组你转完以后的新的头节点。此处可能涉及到多次逆转。比如第一次逆转完以后链表应当变成 3 -> 2 -> 1 -> 4 -> 5 -> 6 -> 7 -> 8. 第二次逆转完变成 3 -> 2 -> 1 -> 6 -> 5 -> 4 -> 7 -> 8。第三次逆转,发现只有7和8两个节点,不符合逆转条件,则不逆转。
  3. 通过思路2我们可知,第一小组你转完以后,头节点即锁定为3,后面不会发生改变。而值为1的节点首先是持有下一个小组的头结点,即值为4的节点。但是,当下一小组节点发生逆转以后,会更改持有的头节点,会变更为持有值为6的新头节点。最后一次只有2个节点,不满足条件,不需要逆转,直接返回即可。

  • 总结:通过以上分享,我们大体得出结论:第一次逆转锁定整个链表的头节点 每一次逆转后,前一小组的尾结点都需要变更持有下一小组的逆转后的头结点引用对象;如果不满足条件,则直接返回,不做任何变更
package code.code_02;/*** K个节点的组内逆序调整* 给定一个单链表的头节点head,和一个正数k* 实现k个节点的小组内部逆序,如果最后一组不够k个就不调整* 调整前:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8,k = 3* 调整后:3 -> 2 -> 1 -> 6 -> 5 -> 4 -> 7 -> 8** 解题思路:***/
public class ReverseKGroupTest2 {private static  class Node {public V data;public Node next;Node (V _data){this.data = _data;}}// 先设计打印方法,方便检查逆转后结果public void printNode (Node node){if (node == null) {System.out.println("链表不存在");}System.out.println("当前节点的值为: " + node.data);//递归的方式逐层打印Node的子节点if(node.next != null) {printNode(node.next);}}//设计构造单链表的函数public Node initSingleNodeList (int length){if (length <= 0) {return null;}Node head = null;Node cur;Node pre = null;for (int i = 1; i <= length; i++) {cur = new Node<>(i);//头结点一旦确认,将会固定不变if (head == null) {head = cur;}if (pre != null) {pre.next = cur;}pre = cur;}return head;}public Node getEndNodeInKGroup (Node node, int k){/* while (k > 0 && node != null) {node = node.next;k--;}*///以上注释的代码是有bug的写法,边边角角需要注意while (--k > 0 && node != null) {node = node.next;}return node;}public Node reverseKGroup (Node node, int k){Node start = node;Node end = this.getEndNodeInKGroup(start, k);//第一次进入都没有尾节点,说明此链表不符合局部逆转//k个节点的要求,直接返回if (end == null) {return node;}//逆转前的第一个分组尾节点,就是新的头结点Node head = end;/*** 第一次逆转。为什么没有返回值呢?* 因为head已经指向了新的头结点, 此方法做到逆转,* 使链表并没有断.* 此时的head是第一次局部逆转后的值。比如:* 逆转前是 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7* 逆转后是 3 -> 2 -> 1 -> 4 -> 5 -> 6 -> 7*/System.out.println("========外部调用前hash值为: " + end.hashCode() + "======");reverseNode(start, end);System.out.println("========外部调用后hash值为: " + end.hashCode() + "======");System.out.println("+++++++++++++++++++++++++++一次完整的调用结束++++++++++++++++++++++++++++++++");//上一组group你转完以后的尾节点Node lastEnd = start;while (lastEnd.next != null) {/*** 接着逆转* 因为reverseNode(start, end)并没有返回值,因此原有的连* 表并没有断。由于在 reverseNode(start, end)方法中的逆* 转。 此时的start已经持有了下一组待逆转group的头节点处* 可以参考reverseNode(start, end)方法的最后一行代码*/start = lastEnd.next;end = this.getEndNodeInKGroup(start, k);//如果接下来的group不符合算法要求,也就是不满足//k个节点,直接返回if (end == null) {//因为没有发生逆转,前一组已经逆转的尾结点本来就//持有这一组待你转接节点的默认头节点,也就不需要更新了return head;}System.out.println("========外部调用前hash值为: " + end.hashCode() + "======");reverseNode(start, end);System.out.println("========外部调用后hash值为: " + end.hashCode() + "======");System.out.println("+++++++++++++++++++++++++++一次完整的调用结束++++++++++++++++++++++++++++++++");//上一组的尾结点,需要持有本组你转完以后的头结点lastEnd.next = end;//lastEnd来到分组你转完以后的尾节点,为下轮循环做准备lastEnd = start;}//直接返回的是head, 也解释了为什么reverseNode(start, end)//可以没有返回值了.//如果有兴趣,可以去改写的我的算法2中逆转整个链表的代码。将有返回值的逆转//方法也改成没有返回值的方法https://blog.csdn.net/chen_yao_kerr/article/details/127935045?spm=1001.2014.3001.5501return head;}//无参数函数,因此之前的连边不能断private void reverseNode (Node start, Node end){//我们需要提前直到逆转前的end节点的下一个节点//逆转完成以后,新的尾节点指向此节点,保证链表不断//此处有一个问题,此处的end指向了下一个节点,那么end应该是变化了的才对。那么为什么//在代码的122行lastEnd.next = end; 依旧持有值为6的节点,而不是持有值为7的节点呢?//其实,此处的end经过一次赋值,相当于在另一个方法栈中生成了一个新的局部变量,只是//他们的名称相同而已。其实他们根本就不是一个东西 >> 此处我们通过hash值来确认System.out.println("========方法体内部调用前的hash值为: " + end.hashCode() + "======");end = end.next;System.out.println("========方法体内部调用后的hash值为: " + end.hashCode() + "======");Node next = null;Node cur = start; //start节点是新的尾节点,后面还有用。此时定义一个新的临时节点Node pre = null; //已经逆转的节点//开始逆转//此时的end节点是下一组待逆转的头结点while (cur != end) {next = cur.next;cur.next = pre;pre = cur;cur = next;}/*** 此处有2个问题需要解释一下* 问题1: 为什么是start.next 而不是cur.next呢 ?* 原因: 因为cur已经来到了第一个待逆转group的尾结点,也就是* 你转完以后group的头结点处** 问题2:为什么start.next = pre 而不是start.next = cur ?* 原因: 因为我们在方法的开始就设置了end = end.next; 这样可以* 保证我们当前group的节点都可以在87行的while方法中遍历到。* 而cur最后一次是来到了end.next的位置,这已经超出了当前group的* 节点范畴,因此需要往前找一个,也就是上一次逆转的节点*/start.next = end;}public static void main(String[] args) {ReverseKGroupTest2 test = new ReverseKGroupTest2();//此参数可以设计成从UI传递的值int length = 8;//初始化固定长度的链表Node node = test.initSingleNodeList(length);System.out.println("===============测试构造的链表是否正常===================");test.printNode(node);//链表进行按照k个数组进行划分,并进行局部逆转的过程Node n = test.reverseKGroup(node, 3);System.out.println("===============打印局部逆转后的结果===================");test.printNode(n);}
}

结果如下:


===============测试构造的链表是否正常===================
当前节点的值为: 1
当前节点的值为: 2
当前节点的值为: 3
当前节点的值为: 4
当前节点的值为: 5
当前节点的值为: 6
当前节点的值为: 7
当前节点的值为: 8
========外部调用前hash值为: 1163157884======
========方法体内部调用前的hash值为: 1163157884======
========方法体内部调用后的hash值为: 1956725890======
========外部调用后hash值为: 1163157884======
+++++++++++++++++++++++++++一次完整的调用结束++++++++++++++++++++++++++++++++
========外部调用前hash值为: 356573597======
========方法体内部调用前的hash值为: 356573597======
========方法体内部调用后的hash值为: 1735600054======
========外部调用后hash值为: 356573597======
+++++++++++++++++++++++++++一次完整的调用结束++++++++++++++++++++++++++++++++
===============打印局部逆转后的结果===================
当前节点的值为: 3
当前节点的值为: 2
当前节点的值为: 1
当前节点的值为: 6
当前节点的值为: 5
当前节点的值为: 4
当前节点的值为: 7
当前节点的值为: 8

Process finished with exit code 0
 

其实,逐步拆分算法,组成每一个小例子,然后将小例子都理解了,再组合在一起就是一个完整的算法了。先理解这个算法想要干什么,对照自己的例子去实现就可以了。代码里面备注信息很全面,相信对于首次接触这个算法的你会有帮助

 

相关内容

热门资讯

最高法发布6件涉未成年人家庭保... 转自:经济日报5月15日,最高人民法院发布6件涉未成年人家庭保护典型案例,进一步提高全社会对未成年人...
2024中国债务重组市场深度观... 4月17日晚间,某房地产企业发布公告,宣布总规模约95.5亿美元的境外债务重组获得重大进展,同时披露...
关税调整后对美出口订单波动 企... 转自:财联社【关税调整后对美出口订单波动 企业仍面临不确定性】财联社5月15日电,记者近期走访多家外...
富友支付十年“上市梦”:三冲港... 来源:@华夏时报微博华夏时报记者 赵奕 上海报道十年,上海富友支付服务股份有限公司(下称“富友支付”...
首届北京博物馆季将启 百项展览... 中新网北京5月15日电 (记者 徐婧)首届北京博物馆季将于5月18日启幕。活动携手北京各区和近300...
「AI新世代」AI终端竞争白热... 华夏时报(www.chinatimes.net.cn)记者 石飞月 北京报道在AI 2.0时代的军备...
美调查:受关税影响,美国人减少... 转自:海外网海外网5月15日电 标普全球市场财智公司发布的调查报告称,与一年前相比,3/10的美国人...
【云新发布】云南公安2024年... 云南网讯(记者 赵岗)2025年5月15日是第16个全国公安机关打击和防范经济犯罪宣传日。云南省公安...
新人可以选初恋地定情地结婚了 #婚姻登记加文旅新赛道火了#【#新人可以选初恋地定情地结婚了#】今年5月10日起,新修订的《婚姻登记...
京津优质中小学基础教育资源如何... 5月15日,教育部组织京津冀三地教育部门在雄安新区联合推出以“共建共享、协同发展”为主题的京津优质中...
支付宝扣了钱,我才发现「医保共... 晚上好呀,我是简七编辑部的冰冰。这两天,家里感冒的「接力赛」终于轮到我女儿了。去医院挂号、缴费,一切...
美股异动 | 网易(NTES.... 周四,网易(NTES.US)大涨逾11%,报119.52美元。网易公布2025年第一季度业绩,净收入...
MissPep胶原蛋白肽胶囊:...   为什么你的抗衰产品总是无效?  消费者常陷入困惑:明明坚持服用胶原蛋白,为何皱纹依旧、关节卡顿、...
举重亚锦赛落幕 中国队斩获31... 亚洲举重锦标赛15日在浙江江山落下帷幕,最后一个比赛日,李闫在女子87公斤以上级包揽3金,为中国举重...
新华网评:让文明新风浸润网络家... 原标题:新华网评:让文明新风浸润网络家园来源:新华网新华网北京5月15日电 题:让文明新风浸润网络家...
“婴儿高跟鞋”形似“三寸金莲”... 来源:中国新闻周刊近日,在社交平台上,有人晒出部分电商在售卖一款“婴儿高跟鞋”的商品,由于该鞋子形似...
在回看两人救人的7分钟行车记录... 新京报记者 赵敏 编辑 杨海 校对 李立军5月15日下午,山东烟台的网约车司机王涛把车停在路边,躺在...
佰维存储业绩会:高价值产品从第... 5月15日,佰维存储召开2024年度及2025年第一季度业绩说明会。从行业情况来看,虽然存储产业第一...
阳光电源:5月20日将召开20... 证券日报网讯 5月15日晚间,阳光电源发布公告称,公司2024年度及2025年第一季度业绩说明会定于...
端午节送老丈人,什么酒有面子又...   超市货架上清一色的“豪华包装+三位数标价”,结账时总有点心疼钱包。这两年白酒市场经历了比较大的变...