题目:

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

进阶:你可以设计一个只用 O(1) 额外内存空间的算法解决此问题吗?

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reverse-nodes-in-k-group
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

一、模拟

参考 @康建斌学算法 大佬的解题思路,同时感谢评论区的各位提的疑问以及注解~

1.设置虚拟头结点,指向原始头结点将头结点当做普通结点来对待,减少特殊判断,将链表分区为已翻转部分+待翻转部分+未翻转部分;

2.定义两个指针,pre:每次要翻转链表头结点的前一个结点,end:待翻转链表的尾结点,让其初始都指向虚拟结点;

3.对链表进行遍历,首先通过给定的k来循环,找到第一次需要翻转的链表的范围;

4.经过k次循环后,end到达本次待翻转链表的尾结点,需要保存尾结点的下一个结点:ListNode next = end.next,找到待翻转链表的开始结点: ListNode start = pre.next,并断开end与next的连接:end.next = null;

5.对[start,end]区间的结点进行翻转,将这个待翻转的子链表进行操作:

  • 定义三个指针,preNode:前一个结点指针,currNode:当前结点指针,nextNode:下一个结点指针;

  • 然后对待翻转的结点进行循环,循环结束的条件是:当 当前结点为空:

    • 先保存当前结点后面链表: nextNode = currNode.next;

    • 将当前结点指向preNode: currNode.next = preNode;

    • 更新preNoded位置,preNode向后移动指向当前结点:preNode = currNode;更新curNode位置,curNode向后移动,下一个结点变成当前结点:currNode = nextNode;

    • 最后实现全部翻转,currNode为空,返回这时的preNode

5.将pre.next指向翻转后的链表:pre.next = reverse(start);并将已翻转的部分和待翻转的部分连接,尾结点指向它的下一个结点:

  start.next = next;并且将pre和end重置为下一次翻转链表头结点的前一个结点;

6.一直重复上述步骤,直到end为null时,结束遍历,最终返回 dummyHead.next。

java代码:

 1 /**
2 * Definition for singly-linked list.
3 * public class ListNode {
4 * int val;
5 * ListNode next;
6 * ListNode() {}
7 * ListNode(int val) { this.val = val; }
8 * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
9 * }
10 */
11 class Solution {
12 public ListNode reverseKGroup(ListNode head, int k) {
13 //定义一个虚拟结点并指向头结点
14 ListNode dummyHead = new ListNode(0,head);
15 //定义两个指针初始都指向虚拟结点
16 //pre:每次要翻转链表头结点的前一个结点
17 //end:要翻转链表的尾结点
18 ListNode pre = dummyHead;
19 ListNode end = dummyHead;
20 //当到达尾结点的时候退出while循环
21 //找到end的位置
22 while(end.next != null){
23 //end != null:防止end.next为空报错
24 for(int i = 0; i < k && end != null; i++){
25 end = end.next;
26 }
27 //当不足k倍时,直接退出不进行翻转
28 if(end == null) break;
29
30 //翻转的开始结点
31 ListNode start = pre.next;
32 //保存end的下一个结点
33 ListNode next = end.next;
34 //断开end和下一个结点的连接
35 end.next = null;
36 //将pre.next指向翻转后的链表
37 pre.next = reverse(start);
38 //将尾结点指向end的下一个结点
39 start.next = next;
40 //将pre换成下一次翻转链表头结点的前一个结点
41 pre = start;
42 //将end也要换成下一次翻转链表头结点的前一个结点
43 end = start;
44 }
45 //最后返回虚拟头结点的下一个结点=真正的头结点
46 return dummyHead.next;
47 }
48 public ListNode reverse(ListNode head){
49 //当子链表为空或者只有单结点时,直接返回原表
50 if(head == null || head.next == null) return head;
51 //定义三个指针
52 //preNode前一个结点指针
53 //currNode当前结点指针
54 //nextNode下一个结点指针
55 ListNode preNode = null;
56 ListNode currNode = head;
57 ListNode nextNode = null;
58 //循环结束条件是当当前结点为空
59 while(currNode != null){
60 //先保存下一个结点
61 nextNode = currNode.next;
62 //当前结点指向preNode
63 currNode.next = preNode;
64 //更新preNoded位置
65 preNode = currNode;
66 //更新curNode位置
67 currNode = nextNode;
68 }
69 return preNode;
70 }
71 }

 python3代码:

 1 # Definition for singly-linked list.
2 # class ListNode:
3 # def __init__(self, val=0, next=None):
4 # self.val = val
5 # self.next = next
6 class Solution:
7 def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
8 dummyHead = ListNode(0,head)
9 pre, end = dummyHead, dummyHead
10 while end.next:
11 # 确定end的位置
12 i = 0
13 while i < k and end:
14 end = end.next
15 i += 1
16 # end为空
17 if not end:
18 break
19 # start的位置
20 start = pre.next
21 # 保存end的下一个结点并断开连接
22 next = end.next
23 end.next = None
24
25 # 将pre连接已翻转的链表
26 pre.next = self.reverse(start)
27
28 # 将start连接下一个待翻转的链表
29 start.next = next
30 # 更新pre和end的位置,在下一个翻转链表头结点的前一个结点
31 pre = start
32 end = start
33 return dummyHead.next
34
35 def reverse(self, head):
36 # 特殊判断
37 if not head or not head.next:
38 return head
39 cur = head
40 pre = None
41 next = None
42 while cur:
43 # 保存cur下一个结点
44 next = cur.next
45 # 将cur指向pre
46 cur.next = pre
47 # 将pre移动到cur,将cur移动到next
48 pre = cur
49 cur = next
50 return pre

 二、递归
1.设定一个end指针,初始指向head处

2.找到待翻转的k个结点,如果剩余结点的数量小于k,则不需要翻转,直接返回剩下部分的头结点就行;

3.对[head,end)区间的结点进行翻转(翻转的结点不包括end),并返回翻转后的头结点newHead;

4.再以同样的方式,对剩下的结点进行翻转:head.next = reverseKGroup(end, k);

 java代码:

 1 /**
2 * Definition for singly-linked list.
3 * public class ListNode {
4 * int val;
5 * ListNode next;
6 * ListNode() {}
7 * ListNode(int val) { this.val = val; }
8 * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
9 * }
10 */
11 class Solution {
12 public ListNode reverseKGroup(ListNode head, int k) {
13 //特殊判断
14 if(head == null || head.next == null) return head;
15 //设定一个end指针
16 ListNode end = head;
17 for(int i = 0; i < k; i++){
18 //如果剩下的结点不足k个
19 if(end == null) return head;
20 end = end.next;
21 }
22 //翻转前k个元素
23 ListNode newHead = reverse(head, end);
24 //下一轮翻转从end开始
25 head.next = reverseKGroup(end, k);
26
27 return newHead;
28 }
29 public ListNode reverse(ListNode head, ListNode end){
30 //定义两个指针
31 //preNode前一个结点指针
32 //nextNode下一个结点指针
33 ListNode preNode = null;
34 ListNode nextNode = null;
35 //循环结束条件是当head没有到尾结点时
36 while(head != end){
37 //先保存下一个结点
38 nextNode = head.next;
39 //当前结点指向preNode
40 head.next = preNode;
41 //更新preNoded位置
42 preNode = head;
43 //更新head位置
44 head = nextNode;
45 }
46 return preNode;
47 }
48 }

 python3代码:

 1 # Definition for singly-linked list.
2 # class ListNode:
3 # def __init__(self, val=0, next=None):
4 # self.val = val
5 # self.next = next
6 class Solution:
7 def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
8 # 特殊判断
9 if not head or not head.next:
10 return head
11 end = head
12
13 for i in range(k):
14 # not end:end为空,不足k个
15 if not end:
16 return head
17 end = end.next
18
19 # 翻转链表
20 newHead = self.reverse(head, end)
21 # 递归翻转剩下的
22 head.next = self.reverseKGroup(end, k)
23
24 return newHead
25
26 def reverse(self, head, end):
27 pre = None
28 next = None
29 while head != end:
30 # 保存head下一个结点
31 next = head.next
32 # 将head指向pre
33 head.next = pre
34 # 将pre移动到head,将head移动到next
35 pre = head
36 head = next
37 return pre

力扣25(java&python)-K 个一组翻转链表(困难)的更多相关文章

  1. LeetCoded第25题题解--K个一组翻转链表--java--链表

    链表 单链表:链表中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素的引用字段链接在一起. 双链表:与单链表不同的是,双链表的每个节点都含有两个引用字段. 链表优点 灵活分配内存空间 能在O ...

  2. Java实现 LeetCode 25 K个一组翻转链表

    25. K 个一组翻转链表 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度. 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持 ...

  3. LeetCode 25. K 个一组翻转链表 | Python

    25. K 个一组翻转链表 题目来源:https://leetcode-cn.com/problems/reverse-nodes-in-k-group 题目 给你一个链表,每 k 个节点一组进行翻转 ...

  4. leetcode 25. K 个一组翻转链表

    # coding:utf-8 __author__ = "sn" """ 25. K 个一组翻转链表 给你一个链表,每 k 个节点一组进行翻转,请你返 ...

  5. leetcode 24. 两两交换链表中的节点 及 25. K 个一组翻转链表

    24. 两两交换链表中的节点 问题描述 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表. 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换. 示例: 给定 1->2-> ...

  6. [LintCode] Reverse Nodes in k-Group 每k个一组翻转链表

    Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If ...

  7. k个一组翻转链表(java实现)

    题目: 给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度.如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序. 示例 : 给定这 ...

  8. [LeetCode]25. Reverse Nodes in k-Group k个一组翻转链表

    Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. k ...

  9. js 之k个一组翻转链表

    题目描述 将给出的链表中的节点每\ k k 个一组翻转,返回翻转后的链表如果链表中的节点数不是\ k k 的倍数,将最后剩下的节点保持原样你不能更改节点中的值,只能更改节点本身.要求空间复杂度 \ O ...

  10. 力扣——Reverse Nodes in k-Group(K 个一组翻转链表) python实现

    题目描述: 中文: 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度. 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序 ...

随机推荐

  1. docsify + GitHub Page免费搭建个人博客

    docsify生成文档 docsify是一个动态生成文档网站的工具.通过编辑MarkDown文件就能实现简约清爽的文档页面. 先在Github创建项目 创建项目成功后,把项目克隆到本地(以自己的实际地 ...

  2. 2.4G无线音频传输方案市场调研分析

    基本概念   所谓的2.4G音频传输,不是使用标准的wifi和蓝牙协议传输,而是使用私有的2.4G通信协议来实现点对点,一对多和多对一的音频传输.2.4G私有协议音频传输,有这低延时,距离远,声音高清 ...

  3. 3DCAT将携Cloud3D/XR解决方案亮相视博会

    2021年05月10日-12日,亚洲视觉智能与沉浸式产业博览会将在广州·中国进出口商品交易会展展馆隆重开幕!届时,3DCAT实时渲染云将携Cloud3D.CloudXR解决方案惊艳亮相,4.2号展馆H ...

  4. 恶意软件开发(四)通过查找进程名进行DLL注入

    通过进程名查找PID 当我们编写注入器的时候,肯定是希望直接通过进程名进行注入,而不是像上一篇笔记一样通过手动输入PID进行查找. 通过进程名查找PID的步骤如下: (1)创建系统中所有进程的快照 ( ...

  5. JavaScript知识总结 数据类型篇

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1. JavaScript有哪些数据类型,它们的区别? JavaScript共有八种数据类型,分别是 Undefined.Null.Boo ...

  6. 解密prompt系列25. RLHF改良方案之样本标注:RLAIF & SALMON

    上一章我们主要唠了RLHF训练相关的方案,这一章我们主要针对RLHF的样本构建阶段,引入机器标注来降低人工标注的成本.主要介绍两个方案:RLAIF,和IBM的SALMON. RLAIF RLAIF: ...

  7. linux查看资源使用情况

    linux查看资源使用情况 top -c # 查看资源使用情况 top 输出如下内容 top - 14:54:21 up 95 days, 20:03, 3 users, load average: ...

  8. KingbaseES V8R3集群运维案例之---failover故障处理

    ​ 案例说明: 此案例,为KingbaseES V8R3集群failover切换时,通用的故障处理方式.通过对failover.log和recovery.log日志的解读,让大家了解KingbaseE ...

  9. 关于Actor Component的思考--学习斯坦佛UE+C++

    跟着B站的视频学习,感觉自己的头很混乱.所以浅浅总结一下创建Actor Component之后其的作用和相关操作. Actor Component 首先Component为一个组件,源码就是一个类的声 ...

  10. Docker容器编排技术解析与实践

    本文全面探索了容器编排技术的核心概念.工具和高级应用,包括Docker Compose.Kubernetes等主要平台及其高级功能如网络和存储管理.监控.安全等.此外,文章还探讨了这些技术在实际应用中 ...