原题
链表中等1 种解法

#92反转链表 II

只反转链表从 left 到 right 的闭区间,其余节点位置保持不变。

#链表

原题

给你单链表的头指针 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]

提示:

  • 链表中节点数目为 n
  • 1 <= n <= 500
  • -500 <= Node.val <= 500
  • 1 <= left <= right <= n

进阶: 你可以使用一趟扫描完成反转吗?

查看原题

解题主线

  1. 定位区间前驱后,固定 current 在反转区间尾部,连续把 current.next 头插到区间前端。
  2. 每次头插恰好扩大一个已反转节点,执行 right - left 次。

解法 1:区间头插法

走到第 left 个节点的前驱,将区间内后续节点逐个摘下并插到区间最前面。

  • 时间复杂度: O(n),最坏遍历至 right

  • 空间复杂度: O(1)

JAVA
public class Solution {
    static final class ListNode {
        int val;
        ListNode next;
        ListNode(int val) { this.val = val; }
        ListNode(int val, ListNode next) { this.val = val; this.next = next; }
    }

    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 哨兵节点统一处理 left 为 1 时区间前驱不存在的边界。
        // before 固定在区间前,current 固定为反转后区间尾节点。
        // 每轮摘下 current.next 并头插,已反转区间恰好扩展一个节点。
        // 执行 right-left 轮即可覆盖闭区间,区间外链接保持不变。
        if (left < 1 || right < left) {
            throw new IllegalArgumentException("invalid interval");
        }
        ListNode dummy = new ListNode(0, head);
        ListNode before = dummy;
        for (int position = 1; position < left; position++) {
            before = before.next;
            if (before == null) throw new IllegalArgumentException("left exceeds list length");
        }
        ListNode current = before.next;
        if (current == null) throw new IllegalArgumentException("left exceeds list length");

        for (int i = 0; i < right - left; i++) {
            ListNode moved = current.next;
            if (moved == null) throw new IllegalArgumentException("right exceeds list length");
            current.next = moved.next;
            moved.next = before.next;
            before.next = moved;
        }
        return dummy.next;
    }
}

边界与易错点

  • 原实现默认区间合法,越界会空指针;展示代码显式检查 left、right 与链长。
  • 重连的三步顺序不能交换:先摘 next,再接到区间头,最后更新前驱。

整理来源

由旧仓库源码复核、去重并整理;展示代码已按 Java 21 语义修正明显问题。

  • Q092_ReverseListII.java