【leetcode 25】 K 个一组翻转链表

55 阅读2分钟
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

const l3 = new ListNode(5);
const l2 = new ListNode(4, l3);
const l = new ListNode(1, l2);

function reverseKGroup(head: ListNode | null, k: number): ListNode | null {
  function myReverse(head: ListNode, tail: ListNode) {
    //保存该段链表的尾节点的next指针
    let prev = tail.next;

    //保存该段链表的开始节点
    let p: ListNode | null = head;

    while (prev !== tail) {
      //创建nex指针,其指向该链表的第二个节点
      const nex = p!.next;
      //将头节点和尾节点调换位置
      p!.next = prev;
      //将prev赋值为该段链表的开始节点
      prev = p;

      // 将该段链表的开始节点p向后移动一位
      p = nex;
    }

    return [tail, head];
  }

  // 创建哨兵节点
  const dummyNode = new ListNode(0);
  //将哨兵节点作为头节点的直接前驱2+6
  dummyNode.next = head;

  // 将链表分成k段,pre将作为每一段的哨兵节点,其next始终指向该段的开始节点
  let pre = dummyNode;

  //注意,在此循环中head将会发生改变,其指向每一段链表的开始节点
  while (head) {
    //创建tail尾部指针,最终tail将指向每段链表的尾部,初始化为该段的哨兵节点
    let tail: ListNode | null = pre;
    for (let i = 0; i < k; i++) {
      //将tail指针向后移动
      tail = tail.next;
      //按循环正常走完,将退出循环,tail将指向该段链表的尾元素
      if (!tail) {
        //如果循环中途发现tail为null,则证明该段链表的长度不足已反转,则返回整个链表的头节点,也就是哨兵节点的next指向
        return dummyNode.next;
      }
    }

    //当循环完毕,此时tail将指向该段链表的表尾元素

    //创建nex指针,用于保存该段链表尾节点的后一个节点指针,以便反转后重新连接回总链表
    const nex = tail.next;

    //注意,此时开始结点和尾节点替换了位置
    [head, tail] = myReverse(head, tail);

    //将该段链表的哨兵结节 指向修改后的头节点
    pre.next = head;

    //将修改后的该段链表的尾节点重新指回原先的下一个节点
    tail.next = nex;

    //由于tail指向每段链表的尾节点,也相当于下一段链表的哨兵节点,
    // 将pre 赋值为下一段链表的哨兵节点
    pre = tail;

    //head 赋值为下一个链表的首节点
    head = tail.next;

    console.log(tail, "tail");
  }

  //将修改后总链表的哨兵节点的next返回,其指向新链表的开始节点
  return dummyNode.next;
}

console.log(reverseKGroup(l, 2));