[JavaScript / leetcode] 剑指 Offer II 026. 重排链表

95 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

每日刷题 2022.09.28

题目

  • 给定一个单链表 L 的头节点 head ,单链表 L 表示为:
    • L0 → L1 → … → Ln-1 → Ln 
  • 请将其重新排列后变为:
    • L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …
  • 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例

  • 示例1

image.png

输入: head = [1,2,3,4]
输出: [1,4,2,3]
  • 示例2

image.png

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

提示

  • 链表的长度范围为 [1, 5 * 10^4]
  • 1 <= node.val <= 1000

解题思路

  • 根据题意分析:需要交替重新拼接节点,那么就需要知道节点的中点在哪里。
    • 使用快慢指针,找到链表的中点,并记录下来当前的整个链表的长度;
    • 使用数组存放链表节点指针,同时将每个节点的next设置为null;
    • 先取出首位位置接入到链表中,用node作为尾部指针;
    • 使用l,r指向数组中剩余链表两侧,不断取出节点加入到链表尾部,并更新尾部指针,直到l和r相遇;
    • 如果l和r相等,说明还剩余一个节点没有加入链表,将其加入链表尾部。
  • 注意⚠️:当链表长度为1时,不需要执行剩下的操作。

回顾经典的做法

  • 使用三个指针pre、cur、nxt,创建一个新的虚拟头节点(最后输出结果的时候,将其跳过即可,例:head.next)。
  • 每次拼接的时候,需要头节点的下一个指针,指向当前节点cur,然后将nxt等于nxt = cur.next,再将当前节点的下一个指针节点置为null。最后将当前节点指向下一个节点。重复这样的循环进行操作,最终可以得到重排后的链表。

代码

/**
 * @param {ListNode} head
 * @return {void} Do not return anything, modify head in-place instead.
 */
var reorderList = function(head) {
  // 解法: 先快慢指针,再反转后半段链表,之后将两个链表进行合并
  // 快慢指针找到中点
  let slow = head;
  let fast = head;
  // 记录中点的前一个节点
  let pre = null;
  // 记录链表的长度
  let len = 1;
  while (null != fast.next) {
    if (fast.next.next != null) {
      // 快指针跳2
      fast = fast.next.next;
      len += 2;
    }else {
      fast = fast.next;
      len++;
    }
    // 慢指针跳1
    pre = slow;
    slow = slow.next;
  }
  // 循环结束后,fast指针为尾节点,slow指针为中间节点
  if (len == 1) {
    return head;
  }
  // 获取前半段链表
  pre.next = null;
  // slow指针记录了后半段的链表,现在将其进行反转reverse,使用三个指针
  function reverse(slow) {
    let prev = null;
    let cur = slow;
    let next = null;
    while (cur) {
      next = cur.next;
      cur.next = prev;
      prev = cur;
      cur = next;
    }
    return prev;
  }
  slow = reverse(slow);
  // 将两个链表进行合并
  let ans = new ListNode();
  ans.val = 111;
  let ansH = ans;
  while (head || slow) {
    if (head) {
      ans.next = head;
      head = head.next;
      ans = ans.next;
    }
    if (slow) {
      ans.next = slow;
      slow = slow.next;
      ans = ans.next;
    }
  }
  return ansH.next;
};