【算法】92.翻转链表Ⅱ--通俗讲解
一、题目是啥?一句话说清
给你一个链表和两个整数 left 和 right,反转从第 left 个节点到第 right 个节点的子链表,并返回反转后的链表。其他部分保持不变。
示例:
- 输入:head = [1,2,3,4,5], left = 2, right = 4
- 输出:[1,4,3,2,5](反转了从第2到第4个节点)
二、解题核心
使用哑节点简化操作,找到要反转子链表的前一个节点,断开子链表,反转它,然后重新连接回原链表。 这就像把链表的一段剪下来,反转后再缝回去。
三、关键在哪里?(3个核心点)
想理解并解决这道题,必须抓住以下三个关键点:
1. 哑节点(Dummy Node)的使用
- 是什么:在链表头部添加一个哑节点,其 next 指向头节点。
- 为什么重要:当 left 为 1 时,头节点会被反转,哑节点可以避免处理头节点变化的特殊情况,使代码更统一。
2. 找到关键节点
- 是什么:找到要反转子链表的前一个节点(pre)、子链表的开始节点(start)和结束节点(end)。
- 为什么重要:只有准确找到这些节点,才能正确断开和连接子链表。
3. 反转子链表并重新连接
- 是什么:断开子链表后,反转它,然后将反转后的子链表头连接到 pre 的 next,将反转后的子链表尾连接到原链表的后续节点。
- 为什么重要:如果连接错误,链表会断开或形成环。
四、看图理解流程(通俗理解版本)
让我们用链表 1 → 2 → 3 → 4 → 5 和 left=2, right=4 的例子来可视化过程:
-
初始化:
- 创建哑节点 dummy,其 next 指向头节点 1。
- 初始状态:dummy → 1 → 2 → 3 → 4 → 5
-
找到 pre 节点:
- pre 节点是反转部分的前一个节点,即第 left-1 个节点。这里 left=2,所以 pre 是第 1 个节点,即节点 1。
- 从 dummy 移动 left-1=1 步,pre 指向节点 1。
-
找到 start 和 end 节点:
- start 节点是 pre 的 next,即节点 2。
- end 节点是反转部分的最后一个节点,从 start 移动 right-left=2 步,即节点 4。
-
断开子链表:
- 记录 end 的下一个节点 succ,即节点 5。
- 将 end 的 next 设为 null,断开子链表:子链表为 2 → 3 → 4 → null
-
反转子链表:
- 反转子链表:4 → 3 → 2 → null
- 反转后的头节点是 4,尾节点是 2。
-
重新连接:
- 将 pre 的 next(即节点 1 的 next)指向反转后的头节点 4。
- 将反转后的尾节点 2 的 next 指向 succ(节点 5)。
- 最终链表:dummy → 1 → 4 → 3 → 2 → 5
-
返回结果:返回 dummy.next,即节点 1。
五、C++ 代码实现(附详细注释)
#include <iostream>
using namespace std;// 链表节点定义
struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr