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

293 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。


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

题目大意:给你一个链表,删除链表的倒数第 n 个节点,比如下图,将链表中倒数第 2 个节点删除。

image.png

题目中有个进阶要求:支队链表进行一次扫描。

解题思路:

最显而易见的方法:因为链表只能从头节点向尾节点扫描,并且扫描前无法获取链表的长度,因此,只能先扫描一遍,数一数链表中一共有多少个节点,假设节点数量为 l,要删除倒数第 n 个节点,那么再通过第二次,将第 l - n + 1 个节点删除掉就行了。

这个方法扫描了两次链表,没有达到题目的进阶要求。如果只能扫描一次链表的话,我们在扫描到最后一个节点的时候,需要还持有一个变量指向倒数第 n 个节点的前一个节点(因为删除一个节点的操作需要在它的前一个节点上完成,也就是将前一个节点的 next 指针指向后一个节点,这样就在链表中删除了当前节点)。因为我们事先并不知道哪一个节点是最后一个节点,每到秒到一个节点,都有可能是最后一个节点,因此,我们需要一个变量,永远比当前扫描的慢 n 个节点,这样,当扫描到最后一个节点的时候,这个变量指向的就是要删除的节点的前一个节点,然后执行删除操作就可以了。

注意,我们还要考虑链表长度比 n 小的情况,这种情况下,不需要对链表进行操作。

另外,为了减少循环中的判断和空指针的判断,在链表最前面添加一个节点作为辅助。

最终代码:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        ListNode f = head;
        ListNode s = dummy;
        for (int i = 0; i < n; ++i) {
            f = f.next;
        }
        while (f != null) {
            f = f.next;
            s = s.next;
        }
        s.next = s.next.next;
        return dummy.next;
    }
}