给你单链表的头指针 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
进阶: 你可以使用一趟扫描完成反转吗?
解题:
func reverseBetween(head *ListNode, left int, right int) *ListNode {
dummy := &ListNode{0, head}
start, i := dummy, 0
r, end, begin := &ListNode{}, &ListNode{}, &ListNode{}
for i <= right {
if i == left {
end = start
r = start
start = start.Next
} else if i > left {
temp := start.Next
start.Next = r
r = start
start = temp
} else {
begin = start
start = start.Next
}
i++
}
end.Next = start
begin.Next = r
return dummy.Next
}
官方解答:
1.穿针引线
func reverseLinkedList(head *ListNode) {
var pre *ListNode
cur := head
for cur != nil {
next := cur.Next
cur.Next = pre
pre = cur
cur = next
}
}
func reverseBetween(head *ListNode, left int, right int) *ListNode {
// 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
dummyNode := &ListNode{Val: -1}
dummyNode.Next = head
pre := dummyNode
// 第 1 步:从虚拟头节点走 left - 1 步,来到 left 节点的前一个节点
// 建议写在 for 循环里,语义清晰
for i := 0; i < left-1; i++ {
pre = pre.Next
}
// 第 2 步:从 pre 再走 right - left + 1 步,来到 right 节点
rightNode := pre
for i := 0; i < right-left+1; i++ {
rightNode = rightNode.Next
}
// 第 3 步:切断出一个子链表(截取链表)
leftNode := pre.Next
curr := rightNode.Next
// 注意:切断链接
pre.Next = nil
rightNode.Next = nil
// 第 4 步:同第 206 题,反转链表的子区间
reverseLinkedList(leftNode)
// 第 5 步:接回到原来的链表中
pre.Next = rightNode
leftNode.Next = curr
return dummyNode.Next
}
2.一次遍历「穿针引线」反转链表(头插法)
func reverseBetween(head *ListNode, left, right int) *ListNode {
// 设置 dummyNode 是这一类问题的一般做法
dummyNode := &ListNode{Val: -1}
dummyNode.Next = head
pre := dummyNode
for i := 0; i < left-1; i++ {
pre = pre.Next
}
cur := pre.Next
for i := 0; i < right-left; i++ {
next := cur.Next
cur.Next = next.Next
next.Next = pre.Next
pre.Next = next
}
return dummyNode.Next
}