一、题目描述
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
- 1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
二、思路分析
局部反转链表是反转链表的升级版。
反转链表
反转链表,就是把每个结点 next 指针的指向给反过来就行了
需要用到三个指针,它们分别指向目标结点(cur)、目标结点的前驱结点(pre)、目标结点的后继结点(next)。
cur.next = pre:进行反转 。
next用于指向 cur 原本的后继结点,用于定位下一个结点。
局部反转链表
局部反转需要额外注意的是,链表区间反转完之后,将其拼接上原链表的操作。
用leftHead指向整个 反转区间链表的前驱结点
start 指向反转区间的第一个结点,也是反转后的最后一个结点
pre正好指向反转后的区间链表的第一个结点
cur正好指向区间链表的后驱结点
三、AC 代码
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} left
* @param {number} right
* @return {ListNode}
*/
var reverseBetween = function(head, left, right) {
// 定义pre、cur,用leftHead来承接整个区间的前驱结点
let pre,cur,leftHead
// 用上从大佬那学来的dummy技巧
const dummy = new ListNode()
// dummy后继结点是头结点
dummy.next = head
// p是一个游标,用于遍历,最初指向 dummy
let p = dummy
// p往前走 m-1 步,走到整个区间的前驱结点处
for(let i=0;i<left-1;i++){
p = p.next
}
// 缓存这个前驱结点到 leftHead 里
leftHead = p
// start 是反转区间的第一个结点
let start = leftHead.next
// pre 指向start
pre = start
// cur 指向 start 的下一个结点
cur = pre.next
// 对区间里的链表进行反转
for(let i=left;i<right;i++){
let next = cur.next
cur.next = pre
pre = cur
cur = next
}
// leftHead 的后继结点此时为反转后的区间的第一个结点
leftHead.next = pre
// 将区间内反转后的最后一个结点 next 指向 cur
start.next=cur
// dummy.next 永远指向链表头结点
return dummy.next
};
四、总结
- 处理链表的本质,是处理链表结点之间的指针关系
- 局部反转链表要注意的是反转完局部链表后的拼接操作
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情