题目描述
给你一个链表,删除链表的倒数第 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 <= 300 <= Node.val <= 1001 <= n <= sz
进阶: 你能尝试使用一趟扫描实现吗?
题解
方法 1
删除倒数第 n 节点等价于删除逆转后链表正数第 n 个节点
- 逆置链表
- 使用哑节点统一处理头节点和其他节点
- 找到待删除节点前驱
- 删除节点并返回结果链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeNthFromEnd(head *ListNode, n int) *ListNode {
// 1. 逆置链表
head = reverse(head)
// 2. 使用哑节点统一处理头节点和其他节点
dummy := &ListNode{}
dummy.Next = head
// 3. 找到待删除节点前驱
curNode := dummy
for i := 0; i < n-1; i++ {
curNode = curNode.Next
}
// 4. 删除节点并返回结果链表
needDel := curNode.Next
curNode.Next = needDel.Next
needDel.Next = nil
return reverse(dummy.Next)
}
func reverse(head *ListNode) *ListNode {
var prev *ListNode
for head != nil {
next := head.Next
head.Next = prev
prev = head
head = next
}
return prev
}
图示
方法 2 快慢指针
思路:可以让快指针先移动 n 步,然后慢指针去追快指针,当快指针跑到末尾时,慢指针刚好指向待删除节点的前驱。
代码
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeNthFromEnd(head *ListNode, n int) *ListNode {
var slow, fast, dummy, needDel *ListNode
dummy = &ListNode{Next: head}
slow, fast = dummy, dummy
for i := 0; i < n && fast != nil; i++ {
fast = fast.Next
}
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next
}
needDel = slow.Next
slow.Next = needDel.Next
needDel.Next = nil
return dummy.Next
}
图示
用 dummy 解决了下面的特殊情况(首节点是待删除节点)