92. 反转链表 II
其中left和right分别表示要反转的部分的起始和结束位置(从1开始计数)。整个过程分为两个主要步骤:
将p0移动到反转部分的前一个节点。
通过循环反转从left到right部分的链表。
最后,通过调整指针,将反转后的部分重新连接到原链表中。
假设我们有一个链表和给定的left和right值,我们要反转从位置left到位置right的链表部分。以下是可视化的过程,以链表1->2->3->4->5为例,left=2,right=4,目标是反转从节点2到节点4的部分。
初始链表状态:
dummy -> 1 -> 2 -> 3 -> 4 -> 5
↑
p0 (初始位置)
- 移动
p0到left-1的位置,即节点1的位置。
dummy -> 1 -> 2 -> 3 -> 4 -> 5
↑
p0
- 开始反转从
left到right的部分。我们使用pre和cur指针来帮助我们进行反转。pre初始化为null,cur初始化为p0.next,即开始反转的第一个节点。
第一次迭代:
pre = null, cur = 2
dummy -> 1 2 -> 3 -> 4 -> 5
↑ ↑
p0 cur
pre
第二次迭代:
pre = 2, cur = 3
dummy -> 1 2 <- 3 -> 4 -> 5
↑ ↑
p0 cur
pre
第三次迭代:
pre = 3, cur = 4
dummy -> 1 2 <- 3 <- 4 -> 5
↑ ↑
p0 cur
pre
- 完成反转后,重新连接链表的各个部分。将
p0.next.next指向cur,将p0.next指向pre。
dummy -> 1 -> 4 -> 3 -> 2 -> 5
↑ ↑
p0 cur
pre
最终结果:
1 -> 4 -> 3 -> 2 -> 5
通过这个过程,我们成功地反转了从位置2到位置4的链表部分。
在链表反转的过程中,cur、pre和nxt三个指针各自承担着不同的角色和职责:
-
cur(当前节点指针):cur指向当前正在处理的节点。- 在反转过程中,
cur会逐步沿着原链表向前移动。 cur的作用是标记当前操作的节点,确保反转操作能够按顺序逐个节点进行。
-
pre(前置节点指针):pre指向当前节点cur的前一个节点。- 在反转过程中,
pre用于保存cur的前一个节点的信息,因为在反转cur的next指针指向pre之后,原链表中cur的前一个节点的信息会丢失。 pre的作用是在反转时,将当前节点cur的next指针指向它,实现反转。
-
nxt(下一个节点指针):nxt临时存储cur的下一个节点,即cur.next。- 在反转
cur的next指针之前,需要先保存cur.next的信息到nxt,因为一旦cur.next被更新指向pre,cur原本的下一个节点信息就会丢失。 nxt的作用是确保在反转过程中不会丢失对原链表中cur后续节点的访问。
通过这三个指针的协作,可以实现链表的局部或完整反转,同时保证链表的连续性和完整性不被破坏。在反转过程中,cur会逐步向前移动,pre和nxt分别帮助实现反转操作和保持链表的连续性。
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
// 创建一个哑节点,其next指向head,简化边界条件处理
ListNode dummy = new ListNode(0, head), p0 = dummy;
// 将p0移动到反转部分的前一个节点
for (int i = 0; i < left - 1; ++i)
p0 = p0.next;
// 开始反转链表的部分
ListNode pre = null, cur = p0.next;
for (int i = 0; i < right - left + 1; ++i) {
ListNode nxt = cur.next;
cur.next = pre; // 反转指针
pre = cur;
cur = nxt;
}
// 将反转部分与原链表连接
p0.next.next = cur;
p0.next = pre;
// 返回哑节点的下一个节点,即新的头节点
return dummy.next;
}
}

浙公网安备 33010602011771号