【LeetCode】92. 反转链表 II
一、解题思路
- 虚拟头节点:创建
dummy节点指向原链表头节点,统一处理left=1的边界情况。 - 定位前驱节点:通过指针
pre移动left-1次找到反转区间的前驱节点。 - 头插法反转:将反转区间的每个后续节点依次插入到
pre之后,实现原地反转。 - 连接剩余节点:反转完成后自动保持与原链表后续节点的连接。
二、代码实现
type ListNode struct { Val int Next *ListNode } func reverseBetween(head *ListNode, left int, right int) *ListNode { if head == nil || left == right { return head } // 创建虚拟头节点简化边界处理(如left=1时) dummy := &ListNode{Next: head} pre := dummy // 定位到left前驱节点(移动left-1次) for i := 0; i < left-1; i++ { pre = pre.Next } // 头插法翻转区间(right-left次循环) cur := pre.Next for i := 0; i < right-left; i++ { next := cur.Next // 1.保存当前节点的 cur.Next = next.Next // 2.当前节点指向后续未处理节点 next.Next = pre.Next // 3.将next插入到pre之后 pre.Next = next // 4.更新pre的指向 } return dummy.Next }
三、复杂度分析
| 指标 | 说明 |
|---|---|
| 时间复杂度 | O(n):最多遍历链表两次(定位前驱节点+反转操作) |
| 空间复杂度 | O(1):仅使用固定数量指针变量 |
四、运行示例与注释说明
示例1:输入 head = [1,2,3,4,5], left=2, right=4
代码执行过程:
pre定位到节点1(left=2的前驱)- 反转区间的3次循环操作:
- 第1次:将节点3插入到pre后 → 链表变为
1→3→2→4→5 - 第2次:将节点4插入到pre后 → 链表变为
1→4→3→2→5
- 第1次:将节点3插入到pre后 → 链表变为
- 最终输出
[1,4,3,2,5]
示例2:输入 head = [5], left=1, right=1
- 直接返回原链表
[5]
func printList(head *ListNode) { for head != nil { fmt.Printf("%d->", head.Val) head = head.Next } fmt.Println("->nil") } func main() { // 示例1:head = [1,2,3,4,5], left = 2, right = 4 n1 := &ListNode{1, &ListNode{2, &ListNode{3, &ListNode{4, &ListNode{5, nil}}}}} printList(reverseBetween(n1, 2, 4)) // 1->4->3->2->5->nil // 示例2:head = [5], left = 1, right = 1 n2 := &ListNode{5, nil} printList(reverseBetween(n2, 1, 1)) // 5->nil }
五、边界条件处理
| 场景 | 处理方式 |
|---|---|
| 链表为空或单个节点 | 直接返回原链表(代码第2行判断) |
| left=right | 无需反转,直接返回 |
| 反转区间包含头节点 | 虚拟头节点统一处理(无需特殊逻辑) |
六、算法优势
- 原地操作:无需额外空间,仅通过指针调整实现反转
- 逻辑简洁:头插法将复杂指针操作简化为4步循环
- 统一处理:虚拟头节点规避了头节点特殊情况的复杂判断

浙公网安备 33010602011771号