25. K 个一组翻转链表

LeetCode 原题链接 题目

实现思路

这题的核心是:每次先确认后面是否还有 k 个节点,够 k 个才反转,不够 k 个保持原样

  • 使用一个 dummy 节点来简化边界情况的处理。
  • 使用一个指针 prevGroupTail 来记录上一组的尾节点,初始指向 dummy。
  • 每次循环中,先找到当前组的尾节点 currentGroupTail,如果不足 k 个节点则直接返回结果。
  • 反转当前组的节点,反转后原来的组头变成组尾,原来的组尾变成组头。
  • 将上一组的尾节点 prevGroupTail 的 next 指向当前组的尾节点(反转后是新组头),然后更新 prevGroupTail 指向当前组的尾节点(反转后是新组尾),继续处理下一组。

代码实现

var reverseKGroup = function (head, k) {
  let dummy = new ListNode(0, head);
  // 前一组的尾节点
  let prevGroupTail = dummy;

  while (true) {
    // 找到当前组的尾节点
    let currentGroupTail = prevGroupTail;
    for (let i = 0; i < k; i++) {
      currentGroupTail = currentGroupTail.next;
      // 如果剩余节点不足 k 个,则不需要反转,直接返回链表头部
      if (!currentGroupTail) return dummy.next;
    }

    // 记录当前组的头节点以及下一组的头节点
    let currentGroupHead = prevGroupTail.next;
    let nextGroupHead = currentGroupTail.next;

    // 反转当前组,定义两个指向当前组头和尾的指针,prev、cur
    let prev = nextGroupHead;
    let cur = currentGroupHead;
    for (let j = 0; j < k; j++) {
      const temp = cur.next;
      cur.next = prev;
      prev = cur;
      cur = temp;
    }

    // 接回上一组,因为已反转,所以是 currentGroupTail 连接到 prevGroupTail 的 next
    prevGroupTail.next = currentGroupTail;

    // 移动用来指向上一组尾节点的指针,指向当前组的尾节点(因为已反转,所以是 currentGroupHead)
    prevGroupTail = currentGroupHead;
  }
};

复杂度分析

  • 时间复杂度:O(n),每个节点只会被访问和反转有限次。
  • 空间复杂度:O(1),只使用了常数个指针。