0092.反转链表 II

难度:🟡 中等

标签链表

链接92. 反转链表 II

题目描述

给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,并返回 反转后的链表

示例 1:

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

示例 2:

输入:head = [5], left = 1, right = 1
输出:[5]

解题思路

核心思想

本题的目标是在原地反转链表的一个指定区间 [left, right]。这需要我们精确定位到区间的边界,对区间内的节点进行反转,然后将反转后的子链表正确地接回原链表中。

思路选择

迭代法 + 虚拟头节点(Dummy Head) 是解决此问题的标准最优思路。

  • 虚拟头节点:创建一个 dummy 节点,其 next 指向原始的 head。这可以极大地简化边界情况的处理,尤其是当反转区间包含头节点时(即 left = 1)。

  • 定位前驱节点:我们首先需要找到待反转区间的前一个节点,我们称之为 prev。这个节点位于 left - 1 的位置。

  • 头插法反转:从 left 位置的节点开始,我们依次将后面的节点通过“头插法”的方式,移动到 prev 节点的后面。具体来说,就是将 left 后面的节点,逐个地、依次地插入到 prevprev.next 之间。

关键步骤

  1. 创建虚拟头节点let dummy = new ListNode(0, head),并让一个指针 prev 指向它。

  2. 定位前驱节点:将 prev 指针向前移动 left - 1 步,使其到达待反转区间的前一个节点。

  3. 初始化当前节点:用一个 current 指针指向待反转区间的第一个节点,即 prev.next

  4. 循环反转:循环 right - left 次。在每次循环中: a. 定义一个 nextNode 指向 current.next,这是将要被移动到前面的节点。 b. current 跳过 nextNode,直接指向 nextNode.next。 c. 将 nextNode 插入到 prev 之后,即 nextNode.next = prev.next,然后 prev.next = nextNode

  5. 返回结果:所有操作完成后,返回 dummy.next,它指向新链表的头节点。

代码实现

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 * this.val = (val===undefined ? 0 : val)
 * this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} left
 * @param {number} right
 * @return {ListNode}
 */
var reverseBetween = function(head, left, right) {
    if (!head || left === right) return head;

    const dummy = new ListNode(0, head);
    let prev = dummy; // prev 指向待反转区间的前一个节点

    // 1. 移动 prev 到 left - 1 的位置
    for (let i = 0; i < left - 1; i++) {
        prev = prev.next;
    }

    // current 指向待反转区间的第一个节点
    let current = prev.next; 

    // 2. 循环 right - left 次,使用头插法反转
    for (let i = 0; i < right - left; i++) {
        const nextNode = current.next;
        current.next = nextNode.next;
        nextNode.next = prev.next;
        prev.next = nextNode;
    }

    return dummy.next;
};

复杂度分析

  • 时间复杂度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 ""