7936 字
约 26 分钟
7
025.K 个一组翻转链表
无标签

025.K 个一组翻转链表

作者:沉默王二
发布时间:2024-02-08T15:33:41.187+0800


鲁迅说,LeetCode 官方这道题的题目是 K 个一组翻转链表,怎么看怎么别扭,我觉得应该是 K 个一组,翻转链表 或者 翻转链表 K 个一组。缺少断句,不知道是不是我太敏感了(😂)。

技术派阅读地址:https://paicoding.com/column/7/25

  • 语雀专栏地址+密码可通过星球置顶帖查看:https://t.zsxq.com/15rEo9Pdu

  • 这道题可以说完全重写了,给出 2 道大家完全都能掌握的题解(递归和 while 循环)。

  • 增加代码注释,这样大家更容易看懂并掌握题解;

  • 增加参考资料,这样大家可以从零基础直接开刷,减轻新手刷题的阻力;

  • 增加手绘图,这样大家更容易理解解题思路;

  • 增加 ACM 输入输出,这样大家可以在 Intellij IDEA 中进行调试;

  • 增加题解模拟,这样大家可以根据题解模拟整个题解过程,看完会有一种“哦哦”恍然大悟的感觉;

  • 图片上传至 OSS 并配合 CDN,提升大家在技术派网站中的阅读体感。

  • 另外,这一版本会作为 PDF 的终稿随后在星球进行发布。

题意

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那请将最后剩余的节点保持原有顺序。

注:你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

难度

困难

示例

输入:head = [1,2,3,4,5], k = 2

k=2,反转的是

  • 1,2 → 2,1
  • 3,4 → 4,3
  • 5(只有一位了,不是 k 的整数倍,保留原样)

输入:head = [1,2,3,4,5], k = 3

k=3,反转的是

  • 1,2,3 → 3,2,1
  • 4,5(只有 2 位了,不是 k 的整数倍,保留原样)

分析

由于我们刚刚解完 024.两两交换链表中的节点 这道题,所以面对本题时,虽然是 hard 难度,但并不会被它吓到。

比如说,当 k=2 时,其实就是两两交换链表中的节点,只不过,这道题,可能是两两交换,也可能是三三交换,也可能是四四交换,也可能是五五交换……

两两交换、三三交换、四四交换……这些其实就是翻转链表:给你一个有 k 个节点的链表,翻转它。

OK,我们试着来解这道题。

public ListNode reverseList(ListNode head) {
ListNode curr = head; // 当前节点设置为头节点    while (curr != null) {        ListNode nextTemp = curr.next; // 保存当前节点的下一个节点        curr.next = prev; // 翻转当前节点的指向        prev = curr; // 更新 prev 为当前节点        curr = nextTemp; // 移动当前节点到下一个节点    }    return prev; // 返回翻转后的链表头}

假设我们有一个链表:

1->2->3->4->null

目标是将其翻转为:

4->3->2->1->null

我们需要设置两个指针:prev 和 curr。

  • prev 指针初始设置为 null,因为翻转后的链表的第一个节点(原链表的最后一个节点)将指向 null。
  • curr 指针初始设置为 head,即链表的第一个节点。

我们开始遍历链表,对于链表中的每一个节点:

①、保存下一个节点:首先,我们需要保存 curr 节点的下一个节点,因为一旦我们改变 curr 的指向,就会失去访问它原来的下一个节点的方式。这可以通过一个临时变量 nextTemp 实现。

ListNode nextTemp=curr.next;

②、翻转指向:接着,我们将 curr 的 next 指向 prev,这是实现翻转的关键步骤。

curr.next=prev;

③、移动 prev 和 curr:完成上述操作后,我们需要更新 prev 和 curr 指针,以便继续遍历链表。prev 移动到 curr 的位置,curr 则移动到 nextTemp 的位置。

prev=curr;

这个过程一直重复,直到 curr 为 null,即达到链表的末尾。此时,prev 指向的是翻转后的链表的头节点。

完成遍历后,prev 指向的就是翻转后的链表的头节点。

搞定翻转链表的方法后,本题“K 个一组翻转链表”我们就完成了一半了。接下来,我们只需要找出 K 个节点的链表,然后调用翻转链表的方法即可。对吧?

好,我们来解这道题:找出 K 个节点的链表。

public ListNode findK(ListNode head, int k) {
for (int i = 1; i < k; i++) {        tail = tail.next;    }    return tail;}

这个方法很简单,for 循环遍历链表,找到第 k 个节点,返回即可。

OK,我们来总结一下本题:

  • 找出k个待翻转的节点,如果不足k个,则不做翻转,直接返回。
  • 翻转这k个节点,并且获取反转后的第一个节点(也就是翻转前的最后一个节点)
  • 若后面的节点能够翻转,则继续翻转,即,对后方的k个节点继续进行1、2操作
  • 返回先前获取的第一个节点
/**
  • 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) { // 初始化 tail 用于遍历找到第 k 个节点 ListNode tail = head; for (int i = 1; i <= k; i++) { // 如果不足 k 个,则不进行翻转,直接返回原链表头部 if (tail == null) return head; tail = tail.next; } // 翻转当前 k 个元素的链表,并返回新的头节点 ListNode newHead = reverse(head, tail); // 递归处理剩下的链表,并将当前翻转的链表的尾部(原 head)连接到翻转后的剩余链表上 head.next = reverseKGroup(tail, k); return newHead; }
    private ListNode reverse(ListNode head, ListNode tail) { ListNode prev = null; ListNode next; while (head != tail) { // 保存当前节点的下一个节点 next = head.next; // 将当前节点的 next 指向 prev,完成翻转 head.next = prev; // prev 和 head 前进一位 prev = head; head = next; } // 返回翻转后的链表的头节点 return prev; }}

详细解释一下个题解:

  • 遍历寻找第 k 个节点:使用 tail 变量从当前的 head 开始遍历,寻找第 k 个节点。这个过程中如果发现节点数不足 k 个(即 tail 变为 null),则直接返回原始的 head 节点,因为题目要求不足 k 个节点的部分不需要翻转。
  • 翻转当前的 k 个节点:调用 reverse 方法,传入当前的 head 和 tail,tail 是第 k+1 个节点,但不包括在翻转范围内(左闭右开区间 [head, tail))。翻转完成后返回新的头节点,即原来 k 个节点的最后一个节点。
  • 递归处理剩余部分:递归调用 reverseKGroup 方法处理剩余的链表部分。由于翻转后原来的 head 节点变成了当前翻转部分的尾节点,所以将其 next 指向递归调用的结果,以此来连接后续翻转后的链表。
  • reverse 方法:翻转链表的方法,多了一个 tail 参数,用于控制翻转的范围。

当输入 head = [1,2,3,4,5] 和 k = 4 时,我们来模拟一下整个题解过程:

初始状态:

链表为 1 -> 2 -> 3 -> 4 -> 5,我们需要每 4 个节点作为一组进行翻转。

第一次调用 reverseKGroup:

  • 我们尝试找到第 4 个节点,即节点 4。由于我们能成功找到第 4 个节点,这意味着这一组有足够的节点进行翻转。
  • 我们调用 reverse 方法,以节点 1 作为 head,节点 5 作为 tail(不包含在翻转中),进行翻转。
  • 翻转后的链表变为 4 -> 3 -> 2 -> 1 -> null,此时 1 的 next 指向 null,等待连接剩余部分的翻转结果。

递归调用 reverseKGroup 处理剩余部分:

  • 剩余部分为 [5],因为只有一个节点,不足 k 个,所以直接返回该部分。
  • 我们将节点 1(翻转后的尾部)的 next 指向这个剩余部分,即节点 5。

最终结果:

  • 连接后的最终链表为 4 -> 3 -> 2 -> 1 -> 5。
  • 在这个过程中,第一组的四个节点被翻转,而最后一个节点保持不变,因为它不满足翻转的节点数量要求。

整个题解的效率也非常优秀:

总结

这道题的难度是 hard,但是我们通过分析题目,将其拆解成了两个简单的问题:翻转链表和找出 K 个节点的链表。这样,我们就可以轻松解决这道题了。

涉及到的 Java 基础知识,包括:

力扣链接:https://leetcode.cn/problems/reverse-nodes-in-k-group/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

该题解目前只针对**二哥编程星球 **的球友开放,如果你也想一起打卡学习算法的话,扫下面的优惠券加入我们吧,星球目前 4300+ 人,定价 149 元,从当初的 99 元一路涨上来的,所以早就是优势,别再犹豫了。

(优惠券仅 300 张,数量有限)

一个人可以走得很快,但一群人才能走得更远。如果想去面中大厂的话,LeetCode 几乎是必刷的,二哥的 LeetCode 题解通俗易懂、图文并茂,理解给你举一反三的解题能力,冲鸭。

鲁迅说,LeetCode 官方这道题的题目是 K 个一组翻转链表,怎么看怎么别扭,我觉得应该是 K 个一组,翻转链表 或者 翻转链表 K 个一组。缺少断句,不知道是不是我太敏感了(😂)。

技术派阅读地址:https://paicoding.com/column/7/25

  • 语雀专栏地址+密码可通过星球置顶帖查看:https://t.zsxq.com/15rEo9Pdu

  • 这道题可以说完全重写了,给出 2 道大家完全都能掌握的题解(递归和 while 循环)。

  • 增加代码注释,这样大家更容易看懂并掌握题解;

  • 增加参考资料,这样大家可以从零基础直接开刷,减轻新手刷题的阻力;

  • 增加手绘图,这样大家更容易理解解题思路;

  • 增加 ACM 输入输出,这样大家可以在 Intellij IDEA 中进行调试;

  • 增加题解模拟,这样大家可以根据题解模拟整个题解过程,看完会有一种“哦哦”恍然大悟的感觉;

  • 图片上传至 OSS 并配合 CDN,提升大家在技术派网站中的阅读体感。

  • 另外,这一版本会作为 PDF 的终稿随后在星球进行发布。

题意

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那请将最后剩余的节点保持原有顺序。

注:你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

难度

困难

示例

输入:head = [1,2,3,4,5], k = 2

k=2,反转的是

  • 1,2 → 2,1
  • 3,4 → 4,3
  • 5(只有一位了,不是 k 的整数倍,保留原样)

输入:head = [1,2,3,4,5], k = 3

k=3,反转的是

  • 1,2,3 → 3,2,1
  • 4,5(只有 2 位了,不是 k 的整数倍,保留原样)

分析

由于我们刚刚解完 024.两两交换链表中的节点 这道题,所以面对本题时,虽然是 hard 难度,但并不会被它吓到。

比如说,当 k=2 时,其实就是两两交换链表中的节点,只不过,这道题,可能是两两交换,也可能是三三交换,也可能是四四交换,也可能是五五交换……

两两交换、三三交换、四四交换……这些其实就是翻转链表:给你一个有 k 个节点的链表,翻转它。

OK,我们试着来解这道题。

public ListNode reverseList(ListNode head) {
ListNode curr = head; // 当前节点设置为头节点    while (curr != null) {        ListNode nextTemp = curr.next; // 保存当前节点的下一个节点        curr.next = prev; // 翻转当前节点的指向        prev = curr; // 更新 prev 为当前节点        curr = nextTemp; // 移动当前节点到下一个节点    }    return prev; // 返回翻转后的链表头}

假设我们有一个链表:

1->2->3->4->null

目标是将其翻转为:

4->3->2->1->null

我们需要设置两个指针:prev 和 curr。

  • prev 指针初始设置为 null,因为翻转后的链表的第一个节点(原链表的最后一个节点)将指向 null。
  • curr 指针初始设置为 head,即链表的第一个节点。

我们开始遍历链表,对于链表中的每一个节点:

①、保存下一个节点:首先,我们需要保存 curr 节点的下一个节点,因为一旦我们改变 curr 的指向,就会失去访问它原来的下一个节点的方式。这可以通过一个临时变量 nextTemp 实现。

ListNode nextTemp=curr.next;

②、翻转指向:接着,我们将 curr 的 next 指向 prev,这是实现翻转的关键步骤。

curr.next=prev;

③、移动 prev 和 curr:完成上述操作后,我们需要更新 prev 和 curr 指针,以便继续遍历链表。prev 移动到 curr 的位置,curr 则移动到 nextTemp 的位置。

prev=curr;

这个过程一直重复,直到 curr 为 null,即达到链表的末尾。此时,prev 指向的是翻转后的链表的头节点。

完成遍历后,prev 指向的就是翻转后的链表的头节点。

搞定翻转链表的方法后,本题“K 个一组翻转链表”我们就完成了一半了。接下来,我们只需要找出 K 个节点的链表,然后调用翻转链表的方法即可。对吧?

好,我们来解这道题:找出 K 个节点的链表。

public ListNode findK(ListNode head, int k) {
for (int i = 1; i < k; i++) {        tail = tail.next;    }    return tail;}

这个方法很简单,for 循环遍历链表,找到第 k 个节点,返回即可。

OK,我们来总结一下本题:

  • 找出k个待翻转的节点,如果不足k个,则不做翻转,直接返回。
  • 翻转这k个节点,并且获取反转后的第一个节点(也就是翻转前的最后一个节点)
  • 若后面的节点能够翻转,则继续翻转,即,对后方的k个节点继续进行1、2操作
  • 返回先前获取的第一个节点
/**
  • 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) { // 初始化 tail 用于遍历找到第 k 个节点 ListNode tail = head; for (int i = 1; i <= k; i++) { // 如果不足 k 个,则不进行翻转,直接返回原链表头部 if (tail == null) return head; tail = tail.next; } // 翻转当前 k 个元素的链表,并返回新的头节点 ListNode newHead = reverse(head, tail); // 递归处理剩下的链表,并将当前翻转的链表的尾部(原 head)连接到翻转后的剩余链表上 head.next = reverseKGroup(tail, k); return newHead; }
    private ListNode reverse(ListNode head, ListNode tail) { ListNode prev = null; ListNode next; while (head != tail) { // 保存当前节点的下一个节点 next = head.next; // 将当前节点的 next 指向 prev,完成翻转 head.next = prev; // prev 和 head 前进一位 prev = head; head = next; } // 返回翻转后的链表的头节点 return prev; }}

详细解释一下个题解:

  • 遍历寻找第 k 个节点:使用 tail 变量从当前的 head 开始遍历,寻找第 k 个节点。这个过程中如果发现节点数不足 k 个(即 tail 变为 null),则直接返回原始的 head 节点,因为题目要求不足 k 个节点的部分不需要翻转。
  • 翻转当前的 k 个节点:调用 reverse 方法,传入当前的 head 和 tail,tail 是第 k+1 个节点,但不包括在翻转范围内(左闭右开区间 [head, tail))。翻转完成后返回新的头节点,即原来 k 个节点的最后一个节点。
  • 递归处理剩余部分:递归调用 reverseKGroup 方法处理剩余的链表部分。由于翻转后原来的 head 节点变成了当前翻转部分的尾节点,所以将其 next 指向递归调用的结果,以此来连接后续翻转后的链表。
  • reverse 方法:翻转链表的方法,多了一个 tail 参数,用于控制翻转的范围。

当输入 head = [1,2,3,4,5] 和 k = 4 时,我们来模拟一下整个题解过程:

初始状态:

链表为 1 -> 2 -> 3 -> 4 -> 5,我们需要每 4 个节点作为一组进行翻转。

第一次调用 reverseKGroup:

  • 我们尝试找到第 4 个节点,即节点 4。由于我们能成功找到第 4 个节点,这意味着这一组有足够的节点进行翻转。
  • 我们调用 reverse 方法,以节点 1 作为 head,节点 5 作为 tail(不包含在翻转中),进行翻转。
  • 翻转后的链表变为 4 -> 3 -> 2 -> 1 -> null,此时 1 的 next 指向 null,等待连接剩余部分的翻转结果。

递归调用 reverseKGroup 处理剩余部分:

  • 剩余部分为 [5],因为只有一个节点,不足 k 个,所以直接返回该部分。
  • 我们将节点 1(翻转后的尾部)的 next 指向这个剩余部分,即节点 5。

最终结果:

  • 连接后的最终链表为 4 -> 3 -> 2 -> 1 -> 5。
  • 在这个过程中,第一组的四个节点被翻转,而最后一个节点保持不变,因为它不满足翻转的节点数量要求。

整个题解的效率也非常优秀:

总结

这道题的难度是 hard,但是我们通过分析题目,将其拆解成了两个简单的问题:翻转链表和找出 K 个节点的链表。这样,我们就可以轻松解决这道题了。

涉及到的 Java 基础知识,包括:

力扣链接:https://leetcode.cn/problems/reverse-nodes-in-k-group/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

该题解目前只针对**二哥编程星球 **的球友开放,如果你也想一起打卡学习算法的话,扫下面的优惠券加入我们吧,星球目前 4300+ 人,定价 149 元,从当初的 99 元一路涨上来的,所以早就是优势,别再犹豫了。

(优惠券仅 300 张,数量有限)

一个人可以走得很快,但一群人才能走得更远。如果想去面中大厂的话,LeetCode 几乎是必刷的,二哥的 LeetCode 题解通俗易懂、图文并茂,理解给你举一反三的解题能力,冲鸭。

鲁迅说,LeetCode 官方这道题的题目是 K 个一组翻转链表,怎么看怎么别扭,我觉得应该是 K 个一组,翻转链表 或者 翻转链表 K 个一组。缺少断句,不知道是不是我太敏感了(😂)。

技术派阅读地址:https://paicoding.com/column/7/25

  • 语雀专栏地址+密码可通过星球置顶帖查看:https://t.zsxq.com/15rEo9Pdu

  • 这道题可以说完全重写了,给出 2 道大家完全都能掌握的题解(递归和 while 循环)。

  • 增加代码注释,这样大家更容易看懂并掌握题解;

  • 增加参考资料,这样大家可以从零基础直接开刷,减轻新手刷题的阻力;

  • 增加手绘图,这样大家更容易理解解题思路;

  • 增加 ACM 输入输出,这样大家可以在 Intellij IDEA 中进行调试;

  • 增加题解模拟,这样大家可以根据题解模拟整个题解过程,看完会有一种“哦哦”恍然大悟的感觉;

  • 图片上传至 OSS 并配合 CDN,提升大家在技术派网站中的阅读体感。

  • 另外,这一版本会作为 PDF 的终稿随后在星球进行发布。

题意

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那请将最后剩余的节点保持原有顺序。

注:你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

难度

困难

示例

输入:head = [1,2,3,4,5], k = 2

k=2,反转的是

  • 1,2 → 2,1
  • 3,4 → 4,3
  • 5(只有一位了,不是 k 的整数倍,保留原样)

输入:head = [1,2,3,4,5], k = 3

k=3,反转的是

  • 1,2,3 → 3,2,1
  • 4,5(只有 2 位了,不是 k 的整数倍,保留原样)

分析

由于我们刚刚解完 024.两两交换链表中的节点 这道题,所以面对本题时,虽然是 hard 难度,但并不会被它吓到。

比如说,当 k=2 时,其实就是两两交换链表中的节点,只不过,这道题,可能是两两交换,也可能是三三交换,也可能是四四交换,也可能是五五交换……

两两交换、三三交换、四四交换……这些其实就是翻转链表:给你一个有 k 个节点的链表,翻转它。

OK,我们试着来解这道题。

public ListNode reverseList(ListNode head) {
ListNode curr = head; // 当前节点设置为头节点    while (curr != null) {        ListNode nextTemp = curr.next; // 保存当前节点的下一个节点        curr.next = prev; // 翻转当前节点的指向        prev = curr; // 更新 prev 为当前节点        curr = nextTemp; // 移动当前节点到下一个节点    }    return prev; // 返回翻转后的链表头}

假设我们有一个链表:

1->2->3->4->null

目标是将其翻转为:

4->3->2->1->null

我们需要设置两个指针:prev 和 curr。

  • prev 指针初始设置为 null,因为翻转后的链表的第一个节点(原链表的最后一个节点)将指向 null。
  • curr 指针初始设置为 head,即链表的第一个节点。

我们开始遍历链表,对于链表中的每一个节点:

①、保存下一个节点:首先,我们需要保存 curr 节点的下一个节点,因为一旦我们改变 curr 的指向,就会失去访问它原来的下一个节点的方式。这可以通过一个临时变量 nextTemp 实现。

ListNode nextTemp=curr.next;

②、翻转指向:接着,我们将 curr 的 next 指向 prev,这是实现翻转的关键步骤。

curr.next=prev;

③、移动 prev 和 curr:完成上述操作后,我们需要更新 prev 和 curr 指针,以便继续遍历链表。prev 移动到 curr 的位置,curr 则移动到 nextTemp 的位置。

prev=curr;

这个过程一直重复,直到 curr 为 null,即达到链表的末尾。此时,prev 指向的是翻转后的链表的头节点。

完成遍历后,prev 指向的就是翻转后的链表的头节点。

搞定翻转链表的方法后,本题“K 个一组翻转链表”我们就完成了一半了。接下来,我们只需要找出 K 个节点的链表,然后调用翻转链表的方法即可。对吧?

好,我们来解这道题:找出 K 个节点的链表。

public ListNode findK(ListNode head, int k) {
for (int i = 1; i < k; i++) {        tail = tail.next;    }    return tail;}

这个方法很简单,for 循环遍历链表,找到第 k 个节点,返回即可。

OK,我们来总结一下本题:

  • 找出k个待翻转的节点,如果不足k个,则不做翻转,直接返回。
  • 翻转这k个节点,并且获取反转后的第一个节点(也就是翻转前的最后一个节点)
  • 若后面的节点能够翻转,则继续翻转,即,对后方的k个节点继续进行1、2操作
  • 返回先前获取的第一个节点
/**
  • 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) { // 初始化 tail 用于遍历找到第 k 个节点 ListNode tail = head; for (int i = 1; i <= k; i++) { // 如果不足 k 个,则不进行翻转,直接返回原链表头部 if (tail == null) return head; tail = tail.next; } // 翻转当前 k 个元素的链表,并返回新的头节点 ListNode newHead = reverse(head, tail); // 递归处理剩下的链表,并将当前翻转的链表的尾部(原 head)连接到翻转后的剩余链表上 head.next = reverseKGroup(tail, k); return newHead; }
    private ListNode reverse(ListNode head, ListNode tail) { ListNode prev = null; ListNode next; while (head != tail) { // 保存当前节点的下一个节点 next = head.next; // 将当前节点的 next 指向 prev,完成翻转 head.next = prev; // prev 和 head 前进一位 prev = head; head = next; } // 返回翻转后的链表的头节点 return prev; }}

详细解释一下个题解:

  • 遍历寻找第 k 个节点:使用 tail 变量从当前的 head 开始遍历,寻找第 k 个节点。这个过程中如果发现节点数不足 k 个(即 tail 变为 null),则直接返回原始的 head 节点,因为题目要求不足 k 个节点的部分不需要翻转。
  • 翻转当前的 k 个节点:调用 reverse 方法,传入当前的 head 和 tail,tail 是第 k+1 个节点,但不包括在翻转范围内(左闭右开区间 [head, tail))。翻转完成后返回新的头节点,即原来 k 个节点的最后一个节点。
  • 递归处理剩余部分:递归调用 reverseKGroup 方法处理剩余的链表部分。由于翻转后原来的 head 节点变成了当前翻转部分的尾节点,所以将其 next 指向递归调用的结果,以此来连接后续翻转后的链表。
  • reverse 方法:翻转链表的方法,多了一个 tail 参数,用于控制翻转的范围。

当输入 head = [1,2,3,4,5] 和 k = 4 时,我们来模拟一下整个题解过程:

初始状态:

链表为 1 -> 2 -> 3 -> 4 -> 5,我们需要每 4 个节点作为一组进行翻转。

第一次调用 reverseKGroup:

  • 我们尝试找到第 4 个节点,即节点 4。由于我们能成功找到第 4 个节点,这意味着这一组有足够的节点进行翻转。
  • 我们调用 reverse 方法,以节点 1 作为 head,节点 5 作为 tail(不包含在翻转中),进行翻转。
  • 翻转后的链表变为 4 -> 3 -> 2 -> 1 -> null,此时 1 的 next 指向 null,等待连接剩余部分的翻转结果。

递归调用 reverseKGroup 处理剩余部分:

  • 剩余部分为 [5],因为只有一个节点,不足 k 个,所以直接返回该部分。
  • 我们将节点 1(翻转后的尾部)的 next 指向这个剩余部分,即节点 5。

最终结果:

  • 连接后的最终链表为 4 -> 3 -> 2 -> 1 -> 5。
  • 在这个过程中,第一组的四个节点被翻转,而最后一个节点保持不变,因为它不满足翻转的节点数量要求。

整个题解的效率也非常优秀:

总结

这道题的难度是 hard,但是我们通过分析题目,将其拆解成了两个简单的问题:翻转链表和找出 K 个节点的链表。这样,我们就可以轻松解决这道题了。

涉及到的 Java 基础知识,包括:

力扣链接:https://leetcode.cn/problems/reverse-nodes-in-k-group/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

该题解目前只针对**二哥编程星球 **的球友开放,如果你也想一起打卡学习算法的话,扫下面的优惠券加入我们吧,星球目前 4300+ 人,定价 149 元,从当初的 99 元一路涨上来的,所以早就是优势,别再犹豫了。

(优惠券仅 300 张,数量有限)

一个人可以走得很快,但一群人才能走得更远。如果想去面中大厂的话,LeetCode 几乎是必刷的,二哥的 LeetCode 题解通俗易懂、图文并茂,理解给你举一反三的解题能力,冲鸭。

            知识星球
            
    
    
        
        扫码加入星球
        查看更多优质内容
    
    https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412
025.K 个一组翻转链表
https://clxhxhhr.top/posts/2450/
作者
clxstart
发布于
2026-09-19
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。
☰ 文章目录