algo

19. 删除链表的倒数第 N 个结点

leecode原题

题目

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例

示例 1:

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

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

提示:

进阶:

你能尝试使用一趟扫描实现吗?

解题思路

思路

下面直接引用的是代码随想录(很优秀的教程)里的讲解。

双指针的经典应用: 如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。

思路是这样的,但要注意一些细节。

分为如下几步:

首先这里我推荐大家使用虚拟头结点,这样方便处理删除实际头结点的逻辑。

  1. 定义fast指针和slow指针,初始值为虚拟头结点,如图:

  2. fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:

  3. fast和slow同时移动,直到fast指向末尾,如题:

  4. 删除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
}