当前位置:网站首页>25.K个一组翻转链表
25.K个一组翻转链表
2022-07-01 03:28:00 【兀坐晴窗独饮茶】

思路一 改变链表方向+分组反转
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
// 创建保护节点
ListNode protect = new ListNode(-1, head);
ListNode last = protect;
while(head != null) {
// 获取节点尾部
// 如果不满足条件, 比如 仅剩2个节点, 但是要返回3组, 就会直接返回null
ListNode tail = getTail(head, k);
// 边界问题 : tail = null , 最后一组不满足 k 个
if (tail == null) {
break;
}
// 记录尾部节点的下一个节点
ListNode nextNode = tail.next;
// 反转 head 到 tail 之间 n - 1 条边
reverse(head, tail);
// 上一组的尾部(未反转前的头部)指向当前组的头部(未反转前的尾部)
last.next = tail;
head.next = nextNode;
// 向后移动
last = head;
head = nextNode;
}
return protect.next;
}
public ListNode getTail(ListNode head, int k){
int walk = k - 1; // 实际要走的步数
if(walk <= 0) {
return head;
}
for(int i = 0; head != null && i < walk; i++ ) {
head = head.next;
}
return head;
}
private void reverse(ListNode head, ListNode tail){
if (head == tail) {
return;
}
// 这里注意, 我们不需要改变第一个节点的边的指向
// 所以原先 last = null => last = head , 向后移动一位
ListNode last = head;
head = head.next;
while(head != tail) {
ListNode nextNode = head.next;
// 改变边的方向
head.next = last;
// 指针向后移动
last = head;
head = nextNode;
}
// 注意 head 移动到 tail 位置时, 最后一条边的方向还未改变
tail.next = last;
}
}
基本思路如下 :
主体思路很简单, 分组去反转对应部分的链表, 然后再去考虑和当前组前面和后面节点的链接
首先我们要实现一个获取链表尾部的方法 :
- 传入
head和 链表的个数n返回链表的尾部
public ListNode getTail(ListNode head, int k){
int walk = k - 1; // 实际要走的步数
if(walk <= 0) {
return head;
}
for(int i = 0; head != null && i < walk; i++ ) {
head = head.next;
}
return head;
}
代码很简单, 但是要注意一些细节 :
- 我们要从head移动k步到尾部, 所以实际走的步数数 k - 1, 因为默认就在 head 上.
head != null这个条件, 当 最后一组的链表节点个数小于 k - 1的时候, 这个时候 还未循环结束, head 可能就走到了链表的末尾, 注意 : 此时 我们要返回的 tail 并不是链表的末尾, 而是 null
其次我们要将 链表的头部和尾部节点传入到 reverse 方法内去反转链表的边, 这个思路和 206.反转链表 的思路基本一致, 但是有一点不同
private void reverse(ListNode head, ListNode tail){
if (head == tail) {
return;
}
// 这里注意, 我们不需要改变第一个节点的边的指向
// 所以原先 last = null => last = head , 向后移动一位
ListNode last = head;
head = head.next;
while(head != tail) {
ListNode nextNode = head.next;
// 改变边的方向
head.next = last;
// 指针向后移动
last = head;
head = nextNode;
}
// 注意 head 移动到 tail 位置时, 最后一条边的方向还未改变
tail.next = last;
}
注意细节 :

反转链表时, 初始状态 last 是指向 null 的, 假如有5个节点, 我们实际上要反转 5条边, 包含开头指向null的边
但是在这道题里面, 我们仅仅需要反转 n - 1 条边,如下图, 实际上我们要反转的是 节点 1 到 节点 2 的边即可

细节问题: 如果head和tial指向同一个节点, 我们就不需要反转边

if (head == tail) {
return;
}
然后, 我们需要把反转后的链表和其他节点连接, 另外需要注意的是, 我们考虑问题先考虑整体, 再考虑细节, 所以我们考虑中间的节点, 因为中间的节点不存在边界问题 :
public ListNode reverseKGroup(ListNode head, int k) {
// 创建保护节点
ListNode protect = new ListNode(-1, head);
ListNode last = protect;
while(head != null) {
// 获取节点尾部
// 如果不满足条件, 比如 仅剩2个节点, 但是要返回3组, 就会直接返回null
ListNode tail = getTail(head, k);
// 边界问题 : tail = null , 最后一组不满足 k 个
if (tail == null) {
break;
}
// 记录尾部节点的下一个节点
ListNode nextNode = tail.next;
// 反转 head 到 tail 之间 n - 1 条边
reverse(head, tail);
// 上一组的尾部(未反转前的头部)指向当前组的头部(未反转前的尾部)
last.next = tail;
head.next = nextNode;
// 向后移动
last = head;
head = nextNode;
}
return protect.next;
}

首先在反转链表之前需要记录尾部节点4的下一个节点5 : ListNode nextNode = tail.next; 因为反转以后, 节点 4 和 5之间的连接就断了
其次就是对链表进行反转, 然后将当前组和上一组的尾部与下一组的头部连接 :
- 前一组的尾部节点 1 指向反转后的头部节点 4 (未反转前的尾部节点) :
last.next = tail; - 当前组的尾部节点 3 (未反转前的头部节点) 指向 之前记录的节点 5
head.next = nextNode;
最后我们需要重新修改last节点指向当前组的尾部节点, 修改head节点指向下一组的头部节点
// 向后移动
last = head;
head = nextNode;
另外注意细节问题: 最后一组不满足k个的时候, 我们不需要反转, 所以当我们获取尾部以后 需要判断下
// 边界问题 : tail = null , 最后一组不满足 k 个
if (tail == null) {
break;
}
其次是保护节点 : 之所以要有保护节点的原因是, 我们考虑问题是考虑中间组的节点, 但是对于头结点来说, 它没有上一组的节点, 且无法获取 last (也就是上一组的尾结点) , 但是保护节点就可以很好的解决问题 :

初始时 last 直接指向 protect 节点即可, 头结点也不需要考虑边界问题.
完整代码如下 :
package cn.knightzz.leetcode.hard;
import cn.knightzz.link.ListNode;
import static cn.knightzz.link.utils.ListNodeUtils.*;
@SuppressWarnings("all")
public class LeetCode25 {
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
// 创建保护节点
ListNode protect = new ListNode(-1, head);
ListNode last = protect;
while(head != null) {
// 获取节点尾部
// 如果不满足条件, 比如 仅剩2个节点, 但是要返回3组, 就会直接返回null
ListNode tail = getTail(head, k);
// 边界问题 : tail = null , 最后一组不满足 k 个
if (tail == null) {
break;
}
// 记录尾部节点的下一个节点
ListNode nextNode = tail.next;
// 反转 head 到 tail 之间 n - 1 条边
reverse(head, tail);
// 上一组的尾部(未反转前的头部)指向当前组的头部(未反转前的尾部)
last.next = tail;
head.next = nextNode;
// 向后移动
last = head;
head = nextNode;
}
return protect.next;
}
public ListNode getTail(ListNode head, int k){
int walk = k - 1; // 实际要走的步数
if(walk <= 0) {
return head;
}
for(int i = 0; head != null && i < walk; i++ ) {
head = head.next;
}
return head;
}
private void reverse(ListNode head, ListNode tail){
if (head == tail) {
return;
}
// 这里注意, 我们不需要改变第一个节点的边的指向
// 所以原先 last = null => last = head , 向后移动一位
ListNode last = head;
head = head.next;
while(head != tail) {
ListNode nextNode = head.next;
// 改变边的方向
head.next = last;
// 指针向后移动
last = head;
head = nextNode;
}
// 注意 head 移动到 tail 位置时, 最后一条边的方向还未改变
tail.next = last;
}
}
}
思路二 计算链表长度+递归法反转
这个方法的思路很简单 : 先计算链表长度, 然后和 k 求余得到总共要反转多少组, 然后分组翻转即可
时间复杂度 O n O_{n} On
- 实现反转前n项的方法
reverseN(ListNode head, int n) - 实现反转第n到m个元素的方法 :
reverseBetwwen(ListNode head, int n , int m) - 计算链表长度, 然后通过求余得到反转的组数
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
int count = 1;
ListNode p = head;
while(p.next != null) {
p = p.next;
count++;
}
int nums = count / k;
int left = 1;
int right = k;
ListNode node = head;
for (int i = 0; i < nums; i++) {
node = reverseBetween(node, left, right);
left += k;
right+= k;
}
return node;
}
public ListNode reverseBetween(ListNode node, int left, int right) {
if (node == null || node.next == null || left >= right) {
return node;
}
int count = left;
// 创建虚拟头节点 [关键]
ListNode pre = new ListNode(-1, node);
ListNode p = pre;
while(count != 1) {
p = p.next;
count--;
}
ListNode head = reverseN(p.next,right - left + 1);
p.next = head;
return pre.next;
}
public ListNode reverseN(ListNode head, int n){
// 边界条件
if (n == 1) {
return head;
}
// 翻后转链表的头部
ListNode tail = reverseN(head.next, n - 1);
// 翻转链表的头部 , 注意 tail.next = null / 第 n + 1 个节点
ListNode p = head.next;
// 原因是 如果顺序反了, tail指向的目标会丢失
head.next = p.next;
p.next = head;
return tail;
}
}
边栏推荐
- [TA frost wolf \u may - "hundred people plan"] 2.1 color space
- 6. Z 字形变换
- Addition without addition, subtraction, multiplication and division
- [ta - Frost Wolf May - 100 people plan] 1.2.1 base vectorielle
- 【TA-霜狼_may-《百人计划》】2.2 模型与材质空间
- 在线公网安备案保姆级教程【伸手党福利】
- 【TA-霜狼_may-《百人计划》】1.2.1 向量基础
- Leetcode 128 longest continuous sequence (hash set)
- [TA frost wolf \u may- hundred talents plan] 1.2.2 matrix calculation
- 242. valid Letter heteronyms
猜你喜欢
![[ta- frost wolf \u may- hundred people plan] 2.2 model and material space](/img/93/95ee3d4389ffd227559dc8b3207e1d.png)
[ta- frost wolf \u may- hundred people plan] 2.2 model and material space

jeecgboot输出日志,@Slf4j的使用方法

Are you still wasting brain cells for self-study? This interview note is definitely the ceiling of station C

Appium自动化测试基础 — APPium基本原理

Test function in pychram

Appium automation test foundation -- supplement: c/s architecture and b/s architecture description

【TA-霜狼_may-《百人计划》】1.2.1 向量基础

快速筛选打卡时间日期等数据:EXCEL筛选查找某一时间点是否在某一时间段内

bootsrap中的栅格系统

【TA-霜狼_may-《百人计划》】1.1 渲染流水线
随机推荐
用小程序的技术优势发展产业互联网
MFC window scroll bar usage
241. Design priorities for operational expressions
Idea plug-in backup table
[EI conference] 2022 international joint civil and Offshore Engineering Conference (jccme 2022)
Millet College wechat scanning code login process record and bug resolution
165. 比较版本号
Are you still wasting brain cells for self-study? This interview note is definitely the ceiling of station C
Implement pow (x, n) function
241. 为运算表达式设计优先级
【伸手党福利】开发人员重装系统顺序
165. compare version numbers
318. Maximum word length product
Develop industrial Internet with the technical advantages of small programs
Download and installation configuration of cygwin
Network metering - application layer
FCN full Convolution Network Understanding and Code Implementation (from pytorch Official Implementation)
[TA frost wolf \u may- hundred talents plan] 1.2.3 MVP matrix operation
[TA frost wolf \u may- hundred people plan] 2.3 introduction to common functions
torch. histc