个人评价:链表双指针操作进阶,此题边界判断需要注意!
题目难度:🌟🌟 (参考 LeeCode 简单🌟 、中等🌟 🌟 、困难🌟 🌟 🌟 )
另,通常算法题会考察分析时间复杂度和空间复杂度,可参考笔者之前的文章
删除链表的倒数第 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
解题思路
鉴于上一篇刷了 💯【算法面试】Go题解 5.链表中倒数第k个节点
延续上篇思路,之后应该不难得出:
- 先找到倒数第 N 个节点
- 删除第 N 个节点,返回头节点
不难吧~ 但是!边界需要注意!!!
先来个错误示范,删除第 N 个节点,我们可以简单的使用指针地址改变的方式
参考 LeetCode 237. 删除链表中的节点 增加 *slow = *slow.Next
Go 代码如下:
func removeNthFromEnd(head *ListNode, k int) *ListNode {
slow, fast := head, head
for ; k > 0; k-- {
fast = fast.Next
}
for fast != nil {
slow, fast = slow.Next, fast.Next
}
*slow = *slow.Next
return head
}
https://play.golang.org/p/TRKYrBRjkO3 使用「示例一」 good~
但是!! 注意删除节点,使用地址改变的方式 不适用尾结点,示例二、三 直接 报错啦!
所以,删除节点,我们可找到 slow 指针的前一个,改变其 Next 指向 Next.Next 即可(即使是 nil)
但是,这里又产生一个问题,如果找到的 slow 指针为 head,其前一个会报错!所以,这种情况,我们直接将 head.Next 指向 head.Next 即可 (相当于 return head.Next)
最后,注意删除仅有的一个 head,结果为 nil 的问题!!!示例二
Go 代码如下:
func removeNthFromEnd(head *ListNode, n int) *ListNode {
slow, fast := head, head
for ; n > 0; n-- {
fast = fast.Next
}
//相当于若为倒数第n个,找不到 head 的前一个了
if fast == nil {
return head.Next
}
fast = fast.Next //找倒数第 n+1 个
for fast != nil {
slow, fast = slow.Next, fast.Next
}
if slow.Next == nil {
return nil //删除仅一个 head 节点,返回为 nil
}
slow.Next = slow.Next.Next //相当于删除第 n 个节点
return head
}
总结
上述方法,使用了双指针,尝试使用了一趟扫描实现。但是,边界判断的坑还真不少,所以此题是二星呀~
也可使用其他方式,可参考官方的其他题解(但笔者觉得此类链表题双指针最优)
算法题解,注意测试用例!!!
- 刷题时,LeetCode 示例注意要全部通过(争取一次过🐴)
- 面试时,可能面试官会故意不给边界条件,先别忙着解,问清楚条件很重要!😂 然后尽可能自己先列出测试用例,提交时自测(留下自测代码,这会给面试官留下好印象哦~ ✨)