【力扣】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 的下一个节点记录为 nextnext = 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:指向待反转区域的第一个节点 leftListNode cur = pre.next;// next:永远指向 curr 的下一个节点,循环过程中,curr 变化以后 next 会变化ListNode next;for (int i = 0; i < right - left; i++) {//先将 curr 的下一个节点记录为 nextnext = 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;}
}