题目:

给你链表的头节点 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. 关于黑客网络 for linux,这个游戏的启动解决方法

    原帖位置https://tieba.baidu.com/p/6200215090

  2. day28--Java泛型01

    Java泛型01 1.泛型的理解和好处 看一个需求: 请编写程序,在ArrayList中添加三个Dog对象 Dog对象含有name和age,并输出name和age(要求使用getXXX()) 先用传统 ...

  3. 基于R语言的raster包读取遥感影像

      本文介绍基于R语言中的raster包,读取单张或批量读取多张栅格图像,并对栅格图像数据加以基本处理的方法. 1 包的安装与导入   首先,我们需要配置好对应的R语言包:前面也提到,我们这里选择基于 ...

  4. RunOnWeb - 创建新协议,支持html调用本地可执行文件,支持浏览器互相调用

    浏览器调用 exe ?    Yes!  谷歌 Chrome 启动微软 Edge ?     Yes! RunOnWeb 协议 创建新协议,支持html调用本地可执行文件,支持浏览器互相调用 [最新版 ...

  5. Ubuntu设置初始root密码,开启远程访问

    [Ubuntu设置初始root密码,开启远程访问] 初始化root密码 ubuntu安装好后,root初始密码(默认密码)不知道,需要设置. 先用安装时候的用户登录进入系统 输入:sudo passw ...

  6. 三维模型OBJ格式轻量化的跨平台兼容性问题分析

    三维模型OBJ格式轻量化的跨平台兼容性问题分析 三维模型的OBJ格式轻量化在跨平台兼容性方面具有重要意义,可以确保模型在不同平台和设备上的正确加载和渲染.本文将分析OBJ格式轻量化的跨平台兼容性技术, ...

  7. 记录--webpack和vite原理

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 每次用vite创建项目秒建好,前几天用vue-cli创建了一个项目,足足等了我一分钟,那为什么用 vite 比 webpack 要快 ...

  8. SwiftUI 笔记

    TextField 监听 lost focus 之前有一个初始化方法,传入一个 onEditingChanged closure,但这个方法废弃了,文档中也说了 alternative:使用 Focu ...

  9. 性能测试系列:高可用测试linux常用命令

    一 linux常用 df –h 看磁盘 du –h –max-depth=1 查看当前目录下,各个文件夹大小 ls –lht 查看当前目录下,各个文件大小 top –H –p pid 看进程下线程的资 ...

  10. [Java]Socket套接字(网络编程入门)

    [版权声明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://blog.csdn.net/m0_69908381/article/details/129907893 出自[进步* ...