给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
输入:head = [1], n = 1
输出:[]
输入:head = [1,2], n = 1
输出:[1]
你能尝试使用一趟扫描实现吗?
下面直接引用的是代码随想录(很优秀的教程)里的讲解。
双指针的经典应用: 如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。
思路是这样的,但要注意一些细节。
分为如下几步:
首先这里我推荐大家使用虚拟头结点,这样方便处理删除实际头结点的逻辑。
定义fast指针和slow指针,初始值为虚拟头结点,如图:
fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:
fast和slow同时移动,直到fast指向末尾,如题:
删除slow指向的下一个节点,如图:
type ListNode struct {
Val int
Next *ListNode
}
func removeNthFromEnd(head *ListNode, n int) *ListNode {
vitualHead := &ListNode{}
vitualHead.Next = head
fastNode := vitualHead
slowNode := vitualHead
// fast指针先向前移动n+1位
for fastNode != nil && n > 0 {
fastNode = fastNode.Next
n -= 1
}
// fast和slow指针同时向前移动, 直到fast指针遍历到尾指针
for fastNode != nil {
// 到最后一个节点了
if fastNode.Next == nil {
slowNode.Next = slowNode.Next.Next
break
}
fastNode = fastNode.Next
slowNode = slowNode.Next
}
return vitualHead.Next
}