Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述
给定单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表 。输入:head = [1,2,3,4,5], left = 2, right = 4 输出:[1,4,3,2,5]
输入:head = [1,2,3,4,5], left = 2, right = 4 输出:[1,4,3,2,5]
要求:
- 链表中节点数目为
n 1 <= n <= 500500 <= Node.val <= 5001 <= left <= right <= n
二、思路分析
- 与反转链表1不同的地方在于,只反转链表中的一段节点,就需要记录被反转链表头结点的前一个节点,以及最后一个节点的后一个节点,用于最后拼接反转后的链表。
- 首先从头结点向左遍历
left个位置,找到需要被反转的链表的前置节点。 - 再从该前置节点遍历
right-left+1个位置,找到被反转链表的最后一个节点。 - 到这一步骤问题就被简化为反转链表的问题,调用
reverseList反转需要被反转的链表。 - 记录了前置节点和后续节点,再将其拼接在一块,返回结果。
- 这种方式需要遍历两次,第一次是寻找前置节点,使用
for循环遍历一次,第二次是寻找后置节点for循环遍历一次。
三、AC 代码
func reverseBetween(head *ListNode, left int, right int) *ListNode {
//dummynode 头结点,避免边界操作
dummynode := &ListNode{Next:head}
pre := dummynode
//找到需要反转的left左边的节点
for i := 0;i<left-1;i++ {
pre = pre.Next
}
rightnode := pre
//寻找rightnode
for i := 0 ;i<right-left+1;i++{
rightnode = rightnode.Next
}
//leftnode,rightnode为截取出的链表,切断
leftnode := pre.Next
pre.Next = nil
rightrightNode := rightnode.Next
rightnode.Next = nil
//reverseList
reverseList(leftnode)
//反转后rightnode在左边,leftnode在右边,拼接到一起
pre.Next = rightnode
leftnode.Next = rightrightNode
return dummynode.Next
}
func reverseList(head *ListNode) {
var pre *ListNode
cur := head
for cur != nil {
next := cur.Next
cur.Next = pre
pre = cur
cur = next
}
}
四、总结
反转链表是一道常考的经典题目,反转链表2需要使用到反转链表的方法。在细节上需要处理前置节点和后置节点。需要注意的是,被反转链表的头尾节点,在反转前分别为leftnode和rightnode,反转后头结点为rightnode,尾节点为leftnode ,并且在反转前首先要切割开需要翻转的链表在代码中为pre.Next = nil rightnode.Next = nil 。