文章目录
- [19. 删除链表的倒数第 N 个结点](#19. 删除链表的倒数第 N 个结点)
19. 删除链表的倒数第 N 个结点
题目描述
给你一个链表,删除链表的倒数第 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]
提示:
- 链表中结点的数目为 sz
- 1 <= sz <= 30
- 0 <= Node.val <= 100
- 1 <= n <= sz
解题思路
常用三种方法:
- 双指针一次遍历(推荐):快指针先走 n 步,然后快慢同步移动,快指针到尾时,慢指针在待删除结点的前一个结点。
- 栈:遍历入栈,再弹出 n 次找到目标结点的前驱,修改指针。
- 两次遍历:第一次统计长度 sz,第二次定位到 sz-n 的前驱删除。
双指针法(一次遍历)
否 是 新建哑结点dummy->head fast=slow=dummy fast先走n步 fast到尾? fast与slow同步向前 slow.Next为待删 slow.Next = slow.Next.Next 返回dummy.Next
- 设置
dummy
可以统一删除头结点的场景 - 边界:n 一定合法(1<=n<=sz)
- 时间 O(sz),空间 O(1)
栈法
- 遍历链表全部入栈
- 弹出 n 次,栈顶即为待删结点的前驱
- 修改前驱的 Next 指向
- 时间 O(sz),空间 O(sz)
两次遍历
- 第一次统计长度 sz
- 找到第 sz-n 个结点的前驱并删除
- 时间 O(sz),空间 O(1)
代码要点
- 使用
dummy
统一处理删除头结点 - 快指针先走 n 步,再一起走
- 注意 slow.Next 是否为空的判定
本仓库 19/main.go
给出双指针法实现,并在 main()
中包含示例自检。
完整题解代码
go
package main
import (
"fmt"
)
type ListNode struct {
Val int
Next *ListNode
}
// removeNthFromEnd 双指针法:快指针先走n步,然后快慢同步,快到尾时慢在待删前一个
// 时间复杂度: O(sz);空间复杂度: O(1)
func removeNthFromEnd(head *ListNode, n int) *ListNode {
dummy := &ListNode{Next: head}
fast, slow := dummy, dummy
// fast 先走 n 步
for i := 0; i < n; i++ {
if fast != nil {
fast = fast.Next
}
}
// fast 和 slow 同步走,直到 fast 到尾
for fast != nil && fast.Next != nil {
fast = fast.Next
slow = slow.Next
}
// slow.Next 就是待删除结点
if slow != nil && slow.Next != nil {
slow.Next = slow.Next.Next
}
return dummy.Next
}
// 辅助:从切片构造链表
func buildList(vals []int) *ListNode {
if len(vals) == 0 {
return nil
}
head := &ListNode{Val: vals[0]}
curr := head
for i := 1; i < len(vals); i++ {
curr.Next = &ListNode{Val: vals[i]}
curr = curr.Next
}
return head
}
// 辅助:链表转切片
func listToSlice(head *ListNode) []int {
res := []int{}
for head != nil {
res = append(res, head.Val)
head = head.Next
}
return res
}
func main() {
// 示例1: head=[1,2,3,4,5], n=2 -> [1,2,3,5]
h1 := buildList([]int{1, 2, 3, 4, 5})
ans1 := removeNthFromEnd(h1, 2)
fmt.Printf("示例1: %v\n", listToSlice(ans1))
// 示例2: head=[1], n=1 -> []
h2 := buildList([]int{1})
ans2 := removeNthFromEnd(h2, 1)
fmt.Printf("示例2: %v\n", listToSlice(ans2))
// 示例3: head=[1,2], n=1 -> [1]
h3 := buildList([]int{1, 2})
ans3 := removeNthFromEnd(h3, 1)
fmt.Printf("示例3: %v\n", listToSlice(ans3))
// 额外: 删除头结点场景 head=[1,2], n=2 -> [2]
h4 := buildList([]int{1, 2})
ans4 := removeNthFromEnd(h4, 2)
fmt.Printf("额外: %v\n", listToSlice(ans4))
}