【力扣】92. 反转链表 II
给你单链表的头指针 head 和两个整数 left 和 right ,其中 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
题解
一次遍历「穿针引线」反转链表(头插法)。
思想是:在需要反转的区间里,每遍历到一个节点,让这个新节点来到反转部分的起始位置。
输入:
整个流程:
实现原理:
三个指针变量 pre
、curr
、next
来记录反转的过程中需要的变量,它们的意义如下:
curr
:指向待反转区域的第一个节点 left;next
:永远指向curr
的下一个节点,循环过程中,curr
变化以后next
会变化;pre
:永远指向待反转区域的第一个节点 left 的前一个节点,在循环过程中不变。
具体实现:
- 先将
curr
的下一个节点记录为next
; - 执行操作 ①:把 curr 的下一个节点指向 next 的下一个节点;
- 执行操作 ②:把 next 的下一个节点指向 pre 的下一个节点;
- 执行操作 ③:把 pre 的下一个节点指向 next。
//先将 curr 的下一个节点记录为 next
next = cur.next;
// 操作1:把 curr 的下一个节点指向 next 的下一个节点;
cur.next = next.next;
// 操作2:把 next 的下一个节点指向 pre 的下一个节点
next.next = pre.next;
// 操作3:把 pre 的下一个节点指向 next。
pre.next = next;
完成以后链表拉直后:
同理继续。同样需要注意 穿针引线 操作的先后顺序:
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val;this.next = next; }
}
//整体思想:在需要反转的区间里,每遍历到一个节点,让这个新节点来到反转部分的起始位置
public class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
// 设置 dummyNode 是这一类问题的一般做法
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
// pre:永远指向待反转区域的第一个节点 left 的前一个节点,在循环过程中不变。
ListNode pre = dummyNode;
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
// curr:指向待反转区域的第一个节点 left
ListNode cur = pre.next;
// next:永远指向 curr 的下一个节点,循环过程中,curr 变化以后 next 会变化
ListNode next;
for (int i = 0; i < right - left; i++) {
//先将 curr 的下一个节点记录为 next
next = cur.next;
// 操作1:把 curr 的下一个节点指向 next 的下一个节点;
cur.next = next.next;
// 操作2:把 next 的下一个节点指向 pre 的下一个节点
next.next = pre.next;
// 操作3:把 pre 的下一个节点指向 next。
pre.next = next;
}
return dummyNode.next;
}
}