leetcode92 反转链表II

题目

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

解析

先说最容易理解的方法,这个是从灵山茶艾府那里看到的,先放代码:

func reverseBetween(head *ListNode, left, right int) *ListNode {
	dummy := &ListNode{}
	dummy.Next = head
	pre := dummy
	for i := 0; i < left-1; i++ {
		pre = pre.Next
	}
	leftBefore := pre
	cur := pre.Next
	for i := 0; i < right-left+1; i++ {
		next := cur.Next
		cur.Next = pre
		pre = cur
		cur = next
	}
	leftBefore.Next.Next = cur
	leftBefore.Next = pre
	return dummy.Next
}

这个解法相对于下面的“一次遍历穿针引线头插法”来说,遵循的其实就是每次只改变一个节点,而不是三个节点绕来绕去的;具体分析下上面的代码,意思是我们先定位到left位置的前一个节点,他是pre,同时用了一个leftbefore来标记,为了反转完后再串联起来;再然后根据之前的反转链表的代码,将pre之后的这一段给反转了,循环结束后,此时pre在right的位置上,cur在right的下一个节点上,那么就有:

	leftBefore.Next.Next = cur
	leftBefore.Next = pre

这样就串起来了,这里的P0就是leftBefore
在这里插入图片描述


这道题不太简单,分为两种方法,先说不好理解的那种方法,主要是官方题解中的第二种方法(一次遍历穿针引线头插法),注意这种反转和之前遇到过的都不一样,写的时候很容易出错(在画图的前提下,易错点都在下面代码里了)

代码如下:

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseBetween(head *ListNode, left int, right int) *ListNode {
	dummy := &ListNode{}
	dummy.Next = head
	pre := dummy
	for i := 0; i < left-1; i++ { // 注意这个left和right的值,自己画图的时候就能发现需要-1才合适
		pre = pre.Next // 此时移到了left所在的前一位
	}
	cur := pre.Next
	for i := 0; i < right-left; i++ { // 这个范围想不明白的话也是画图用测试用例来看
		next := cur.Next
		cur.Next = next.Next
		next.Next = pre.Next // 一定要注意这一步,不是指向cur,因为cur后面会走
		pre.Next = next
	}
	return dummy.Next
}

第二种方法是在之前反转链表的基础上改进,稍微好理解一点,直接调用之前的反转链表的方法(当然这个方法也可以改成不需要返回值)

func reverseBase(head *ListNode) *ListNode {
	var pre *ListNode
	cur := head
	for cur != nil {
		next := cur.Next
		cur.Next = pre
		pre = cur
		cur = next
	}
	return pre
}

func reverseBetween(head *ListNode, left int, right int) *ListNode {
	if head == nil {
		return head
	}
	dummy := &ListNode{}
	dummy.Next = head
	pre := dummy
	for i := 0; i < left-1; i++ {
		pre = pre.Next // pre是left节点前面的一个节点
	}

	// 找到right节点
	rightNode := pre.Next
	for i := 0; i < right-left; i++ { // 画图画图,想不明白就画图
		rightNode = rightNode.Next
	}

	// 在此基础上切割出来一个子链表(先保留最后要链接的节点)
	leftNode := pre.Next
	rightAfter := rightNode.Next

	// 切断链表
	pre.Next = nil
	rightNode.Next = nil

	rightNode = reverseBase(leftNode) // 传入的其实是左结点,反转后返回的是右节点了

	// 接回去
	pre.Next = rightNode
	leftNode.Next = rightAfter

	return dummy.Next
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值