0143.重排链表

难度:🟡 中等

标签链表双指针递归

链接143. 重排链表

题目描述

给定一个单链表 L 的头节点 head ,单链表 L 表示为: L₀ → L₁ → … → Lₙ₋₁ → Lₙ 请将其重新排列后变为: L₀ → Lₙ → L₁ → Lₙ₋₁ → L₂ → Lₙ₋₂ → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

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

示例 2:

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

解题思路

核心思想

本题的目标是对链表进行原地重排,将后半部分节点交错地插入到前半部分节点之间。这个问题可以优雅地分解为三个独立的、经典的链表操作子问题:

  1. 找到链表的中间节点。

  2. 反转链表的后半部分。

  3. 合并两个链表(前半部分和反转后的后半部分)。

思路选择

快慢指针 + 链表反转 + 链表合并 是解决此问题的标准最优思路,因为它可以在 O(1) 的额外空间内完成。

  • 寻找中点:使用快慢指针法。快指针每次走两步,慢指针每次走一步。当快指针到达链表末尾时,慢指针正好位于链表的中点。

  • 反转后半段:从中点将链表切断,然后对后半部分链表执行标准的反转操作。

  • 合并链表:将前半部分链表和反转后的后半部分链表进行“拉链式”的交错合并。

关键步骤

  1. 找中点:初始化 slowfast 指针都指向 headfast 每次走两步,slow 每次走一步。当 fast.nextfast.next.next 为空时,slow 就指向了中点或中点前的节点。

  2. 分割与反转: a. 以 slow 为界,将链表分割成前后两半。slow.next 是后半段的头节点。 b. 将前半段的尾部断开,即 slow.next = null。 c. 对后半段链表进行原地反转。

  3. 交错合并: a. 初始化两个指针,head1 指向原链表的头,head2 指向反转后后半段的头。 b. 在循环中,交错地将 head2 的节点插入到 head1 的节点之后。需要临时变量来保存各自的下一个节点,以防链表断裂。

代码实现

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 * this.val = (val===undefined ? 0 : val)
 * this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {void} Do not return anything, modify head in-place instead.
 */
var reorderList = function (head) {
    let slow = head, fast = head;

    // 1. 快慢指针找中点,正确
    while (fast.next !== null && fast.next.next !== null) {
        fast = fast.next.next;
        slow = slow.next;
    }

    // 2. 反转后半部分
    let prev = null, cur = slow.next;
    slow.next = null; // 断开链表

    while (cur !== null) {
        let temp = cur.next;
        cur.next = prev;
        prev = cur;
        cur = temp;
    }

    // 3. 合并前后两半,逻辑清晰
    // head 指向第一部分头,prev 指向第二部分头
    while (head !== null && prev !== null) {
        let temp1 = head.next;
        let temp2 = prev.next;

        head.next = prev;
        prev.next = temp1;

        head = temp1;
        prev = temp2;
    }
};
  • 优点:此实现堪称模板,正确地分解问题并实现了每一步,时空效率都很高。

  • 代码风格: 变量命名清晰,逻辑分支明确,是一个优秀的实现。

复杂度分析

  • 时间复杂度O(n) 其中 n 是链表的节点数。找中点、反转、合并三个步骤都是线性时间复杂度。

  • 空间复杂度O(1) 我们是在原链表上进行操作,只使用了常数个额外变量作为指针,空间消耗是恒定的。

相关题目

总结

本题是链表操作的集大成者,它将几个最基础、最重要的链表操作(找中点、反转、合并)串联起来,形成了一个更复杂的算法。熟练掌握这三个子问题的解法,是解决各类复杂链表问题的关键。

Copyright © Jun 2025 all right reserved,powered by Gitbook该文件修订时间: 2025-07-03 17:35:08

results matching ""

    No results matching ""

    results matching ""

      No results matching ""