原题链接:92. 反转链表 II
解题思路:
- 参考了官方题解中的
方法二: 迭代链接反转
,你可以其中的图片理解。 - 如果你对反转链表不熟悉,可以先尝试206. 反转链表。
- 使用prev和curr指针进行链表反转,先将两个指针移动到m-1和m位置。
- 在进行反转的时候,链表会被分成三段,第一段和第三段不变,中间的第二段被反转。
- 链表完成反转之后,m-1节点即为第一段链表的尾结点。原来的m节点从第二段的头结点,变成了第二段链表的尾结点。curr指针会移动到第三段链表的头结点,如果第三段链表不存在,curr就为
null
。 - 最后将三段链表连接起来即可。需要注意的是,如果m为1,也就是第一段链表不存在的时候,链表的头结点其实已经变成了第二段链表的头结点,因此需要重新设置一次头结点。
/**
* @param {ListNode} head
* @param {number} m
* @param {number} n
* @return {ListNode}
*/
var reverseBetween = function(head, m, n) {
let prev = null // 用于反转的前置指针
let curr = head // 用于反转的当前指针98j9
// 将prev和head都移动m-1次,prev在m-1位置,head在m位置
while (m > 1) {
prev = curr
curr = curr.next
// 每次循环将m减1,控制移动次数
m--
// 移动指针的同时,需要减少n的数量,完成移动后剩下的n次,即为反转链表的次数
n--
}
let prevListTail = prev // prev即为链表反转后,前半段的尾指针
let reversedListTail = curr // curr即为链表反转后,反转部分的尾指针
// 将链表反转n次
while (n > 0) {
// 反转链表节点的通用方法
let next = curr.next
curr.next = prev
prev = curr
curr = next
// 每次循环将n减1,控制移动次数
n--
}
// 如果prevListTail不为空,即为链表中间的一段进行了反转,需要将前半段与反转后的链表头指针连接起来
if (prevListTail) {
// 链表反转后,prev的位置即为反转部分的头指针
prevListTail.next = prev
} else {
// 链表未空,表示链表从头开始反转,反转后的prev即为新链表的头,因此需要重新设置链表的头指针
head = prev
}
// 链表反转后,反转部分原来的头,变成了尾部,而curr已加移出了链表,成为了最后一段链表的头指针
// 因此需要将反转部分的尾指针与最后一段的头指针连接起来,组成新链表
reversedListTail.next = curr
return head
};