翻转链表中的部分,由206题的封装后,处理这一题只需要细心即可
处理好头节点,使用pre进行遍历,保存四处节点,便于后面衔接节点
这里设置dummy节点的原因是防止left=1,此时preLeftNode节点就不存在了
解法一:递归反转
var reverseBetween = function (head, left, right) {
let dummy = new ListNode(-1)
dummy.next = head
let pre = dummy
let cnt = 0
// 保存反转节点的起始以及终点位置
let leftNode = null, rightNode = null
// 保存反转节点前后的节点
let leftConnectNode = null, rightConnectNode = null
while (pre) {
if (cnt === left - 1) {
// 保存起始节点的前一节点
leftConnectNode = pre
// 保存当前反转的起始节点
leftNode = leftConnectNode.next
}
if (cnt === right) {
// 保存反转的终点
rightNode = pre
// 保存终点的下一节点
rightConnectNode = rightNode.next
// 因为要反转,肯定要给终点置空,不然会导致后面的所有都反转
rightNode.next = null // 部分链表的终点
break
}
// 计数器
cnt++
// 挪向下一节点
pre = pre.next
}
// 反转left-right之间的链表
let list = reverse(leftNode)
// 衔接左边部分
leftConnectNode.next = list
// leftNode变成反转后的终点,衔接右边部分
leftNode.next = rightConnectNode
return dummy.next
};
var reverse = function (head) {
if (!head || !head.next) return head
let newHead = reverse(head.next)
head.next.next = head
head.next = null
return newHead
}
解法二:迭代原地反转(推荐)
var reverseBetween = function (head, left, right) {
let dummy = new ListNode(-1);
dummy.next = head;
pre = dummy;
for (let i = 1; i < left; ++i) {
pre = pre.next;
}
let cur = pre.next;
for (let i = 0; i < right - left; ++i) {
let next = cur.next;
cur.next = next.next;
next.next = pre.next;
pre.next = next;
}
return dummy.next;
};
dummy -> 1 -> 2 -> 3 -> 4 -> 5
dummy -> 1 -> 3 -> 2 -> 4 -> 5
dummy -> 1 -> 4 -> 3 -> 2 -> 5