文章目录
- 前言
- 链表反转|K个一组翻转链表
- 解题方法:
- 头插法处理:
- 穿针引线法处理:
- 总结
前言
提示:没有人天生就喜欢一种气味而讨厌另一种气味。文明的暗示而已。
链表反转|K个一组翻转链表
给你链表的头节点 head
,每 k
个节点一组进行翻转,请你返回修改后的链表。
k
是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k
的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
进阶:你可以设计一个只用 O(1)
额外内存空间的算法解决此问题吗?
思路来的很快,重点是代码层面的编写,这个很重要,思路呢?就是常见的头插法和穿针引线法来处理数组反转问题,当然今天我们也是采用这两种方法解决的,那就开始实现他吧😃
解题方法:
头插法处理:
头插法重点在理解虚拟节点上,如果这个问题解决了,相比较而言要比穿针引线要好实现的多😄, 我们试着把链表整体分为3段,一段是已经翻转的,一端是正在反转,一端是未反转的。为了方便翻转,我们需要京链表遍历一边,统计一下链表的长度len,然后将链表进行分组n=len/k,接下来就是循环进行分组翻转链表。 我们尝试这画一些图,能够更有里的说明:
结假设我们开始翻转 4 节点:
具体思路:
- 找到链表的长度 len 分组
- cur.next = cur.next.next; next.next = pre.next; pre.next = next;
- 循环下一次
上代码😄
/*** 方法2:头插法** @param head* @param k* @return*/public static ListNode reverseKGroup2(ListNode head, int k) {ListNode dummyNode = new ListNode(-1);dummyNode.next = head;ListNode cur = head;int len = 0;while (cur != null) {cur = cur.next;len++;}int n = len / k; // 计算出来分几组ListNode pre = dummyNode;cur = head;for(int i = 0; i < n; i++) {for(int j = 0; j < k - 1; j++) { // ? k - 1 画图就知道了ListNode next = cur.next;cur.next = cur.next.next;next.next = pre.next;pre.next = next;}pre = cur; cur = cur.next; // 记得修改指针}return dummyNode.next;}
穿针引线法处理:
这个思路可以回顾一下穿针引线,到底是怎么回事🤣
首先还是将链表分组翻转, 我们就可以一组一组的处理,把他们分成已经翻转的、正在翻转的和未翻转的三部分,同时为了方便处理头节点,我们使用了一个虚拟的节点。
接下来就是遍历,根据k个为一组找到四个关键位置,并使用变量per,start,end,next标记,比如下面的图:
接着我们就开始翻转,对应颜色进行翻转,我们将end.next = null ,直接使用链表翻转,复用链表翻转的常规操作。🤖注意指针的变化,head便是传入方法的参数,我们接着看图:
当然翻转之后,我们接下来就是将原始链表缝起来,这就需要调整指针域,同样这里也要注意指针的变化🤖
接着调整指针进行下一次循环:
总结一下📝
- 遍历找到四个关键位置,复用常规翻转链表
- pre.next = end; start.next = next; 调整指针域
- 调整下一次循环
了解上面的图,代码应该也会写吧🥰
/*** 方法1: 穿针引线法** @param head* @param k* @return*/public static ListNode reverseKGroup(ListNode head, int k) {ListNode dummyNode = new ListNode(-1);dummyNode.next = head;ListNode pre = dummyNode;ListNode end = dummyNode;while (end.next != null) { // 最终结束的地方for (int i = 0; i < k && end != null; i++) {end = end.next; // 找到当前分组的最后一个}if (end == null) {break;}// 找到start nextListNode start = pre.next;ListNode next = end.next;end.next = null; // 思考?pre.next = reverse(start);start.next = next;pre = end;// 调整下一次循环end = pre;}return dummyNode.next;}
复习一下链表反转💕:
private static ListNode reverse(ListNode head) {ListNode pre = null;ListNode cur = head;while(cur != null) {ListNode next = cur.next;cur.next = pre;pre = cur;cur = next;}return pre;}
总结
注意:指针域的变化,多画图更容易理解,链表反转重点,重点,重点!!!