题目描述

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

进阶:你可以设计一个只用 O(1) 额外内存空间的算法解决此问题吗?

示例 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]

思路&js代码

1、模拟

var reverseKGroup = function (head, k) {
  const start = new ListNode(0)
  start.next = head
 
  let prev = start
 
  while (head) {
    let tail = prev
    // 查看剩余部分长度是否大于等于 k
    for (let i = 0; i < k; ++i) {
      tail = tail.next
      if (!tail) {
        return start.next
      }
    }
    const tmp = tail.next
    ;[head, tail] = reverse(head, tail)
    // 把子链表重新接回原链表
    prev.next = head
    tail.next = tmp
 
    prev = tail
    head = tail.next
  }
  return start.next
}
 
// 翻转
function reverse(head, tail) {
  let prev = tail.next
  let curr = head
 
  while (prev !== tail) {
    const tmp = curr.next
    curr.next = prev
 
    prev = curr
    curr = tmp
  }
 
  return [tail, head]
}

2、迭代

var reverseKGroup = function(head, k) {
    // 统计节点个数
    let n = 0;
    for (let cur = head; cur; cur = cur.next) {
        n++;
    }
 
    const dummy = new ListNode(0, head);
    let p0 = dummy;
    let pre = null;
    let cur = head;
 
    // k 个一组处理
    for (; n >= k; n -= k) {
        for (let i = 0; i < k; i++) { // 同 92 题
            const nxt = cur.next;
            cur.next = pre; // 每次循环只修改一个 next,方便大家理解
            pre = cur;
            cur = nxt;
        }
 
        // 见视频
        const nxt = p0.next;
        p0.next.next = cur;
        p0.next = pre;
        p0 = nxt;
    }
    return dummy.next;
};