给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
提示:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
进阶:你能尝试使用一趟扫描实现吗?
摘一个示例做个说明.
示例 1:
如图
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
条件分析:
- 链表删除某一项 -> 需要找到删除的位置
- 返回链表的头结点 -> 返回删除后的链表
解决思路1:
- 根据分析1,说明需要找到删除节点的位置
- 根据分析2,说明需要知道链表的长度
先判断删除的是否是头节点,然后通过循环找到需要删除的位置,再进行循环操作指到需要删除的节点,让节点指向待删除节点的下一个节点.
func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
let index = nodeLength(head) - n
if index == 0 {
// 删除第一个
return head?.next
}
var newHead = head
for _ in 0 ..< index - 1 {
newHead = newHead?.next
}
newHead?.next = newHead?.next?.next
return head;
}
func nodeLength(_ head: ListNode?) -> Int{
if head == nil {
return 0
}
// 通过递归获取长度
return nodeLength(head?.next) + 1
}
解决思路2:
- 根据分析1,说明可以采用快慢指针,先让快指针指向n节点的位置,然后同时让快慢指针移动,直到快指针指向链表末尾.
- 根据分析2,此时慢指针指向的就是倒数第n个节点,直接让慢指针指向下一个节点即可.
创建一个节点,然后让该节点指向链表头节点.然后定义快慢指针,让快指针先移动n位,然后保持快慢指针相差n,当快指针指向末尾的时候,慢指针指向倒数第n个节点.最后让慢指针指向删除的下一个节点即可.
func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
let resultHead = ListNode(-1)
resultHead.next = head
var fast = resultHead
var slow = resultHead
for _ in 0 ..< n {
// 先让快指针指向第n个节点
fast = fast.next!
}
while fast.next != nil {
// 让快慢指针同时指向下一个节点,直到链表结束,此时快慢指针相差n个
fast = fast.next!
slow = slow.next!
}
// 让慢指针指向下一个节点即可
slow.next = slow.next!.next
return resultHead.next
}
解决思路3:
解决思路2优化,还是快慢指针,还是快指针先走,不同与思路2先循环,采用变量判断是否需要让慢指针移动.
一趟扫描,通过哨兵,实现删除.
func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
let resultHead = ListNode(-1)
resultHead.next = head
var fast = resultHead, slow = resultHead, index = 0
while fast.next != nil {
// 让快慢指针同时指向下一个节点,直到链表结束,此时快慢指针相差n个
fast = fast.next!
index += 1
if index > n {
slow = slow.next!
}
}
// 让慢指针指向下一个节点即可
slow.next = slow.next!.next
return resultHead.next
}
测试用例:
let endNode = ListNode.init(0)
let fourNode = ListNode.init(1)
fourNode.next = endNode
let threeNode = ListNode.init(2)
threeNode.next = fourNode
let secondNode = ListNode.init(3)
secondNode.next = threeNode
let firstNode = ListNode.init(4)
firstNode.next = secondNode
let headNode = ListNode.init(5)
headNode.next = firstNode
考察要点:
- 链表
- 双指针