LeetCode 「困难」25.K 个一组翻转链表

sankigan2025-3-10算法LeetCode

K 个一组翻转链表open in new window

题目描述

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

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 8 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例

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

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

解答

思路

  1. 边界条件处理
  • 如果链表为空或 K 小于等于 1,直接返回原链表
  • 如果链表长度小于 K,直接返回原链表
  1. 翻转 K 个节点
  • 使用一个指针遍历链表,找到第 K 个节点
  • 翻转从当前节点到第 K 个节点之间的链表
  • 保存翻转后的子链表的头节点和尾节点
  1. 递归或循环处理剩余部分
  • 将翻转后的子链表的尾节点连接到下一个子链表的头节点
  • 递归或循环处理剩余的链表部分,直到整个链表处理完毕
  1. 返回结果
Code
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
// 用于翻转从 head 开始的 K 个节点
const reverseKNodes = (head, k) => {
  let p = head;
  for (let i = 0; i < k; ++i) {
    if (!p) return null; // 如果不足 K 个节点,返回 null
    p = p.next;
  }

  let prev = null;
  let curr = head;
  let next = null;

  for (let i = 0; i < k; ++i) {
    next = curr.next; // 保存下一个节点
    curr.next = prev; // 翻转当前节点
    prev = curr; // 移动 prev 到当前节点
    curr = next; // 移动 curr 到下一个节点
  }

  head.next = curr; // 连接翻转后的子链表的尾节点到下一个子链表的头节点
  return prev; // 返回翻转后的子链表的头节点
};

var reverseKGroup = function(head, k) {
  if (!head || k <= 1) return head;

  let newHead = reverseKNodes(head, k);
  if (newHead) {
    head.next = reverseKGroup(head.next, k); // 递归处理剩余部分
  }

  return newHead || head; // 如果没有翻转,返回原链表
};

详细解释递归操作:

  1. 翻转当前组

reverseKGroup 函数中,首先调用 reverseKNodes 函数来翻转当前的 K 个节点。这个函数会返回翻转后的子链表的头节点

const newHead = reverseKNodes(head, k);
  • 如果 newHeadnull,说明当前组的长度不足 K,不需要翻转,直接返回原链表
  • 如果 newHead 不为 null,说明当前组已经成功翻转
  1. 递归处理下一组

翻转当前组后,需要处理剩余的链表。递归调用 reverseKGroup 处理剩余的链表部分

if (newHead) {
  head.next = reverseKGroup(head.next, k);
}
  • head 是翻转后当前组的尾节点(原头节点)
  • reverseKGroup(head.next, k) 递归调用处理剩余的链表部分,返回翻转后的下一组链表的头节点
  • 将当前组的尾节点连接到下一组的头节点
  1. 返回结果

最后,返回翻转后的链表的头节点

return newHead || head;
  • 如果 newHead 不为 null,返回翻转后的链表的头节点
  • 如果 newHeadnull,说明当前组没有翻转,返回原链表的头节点
更新于 2025/3/11 16:04:51