Bootstrap

LeetCode 热题 HOT 100 Java题解——19. 删除链表的倒数第N个节点

19. 删除链表的倒数第N个节点

题目:
给定一个链表,删除链表的倒数第 n n n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

双指针,一遍遍历

最简单可以想到的方法肯定是遍历一遍记住长度,之后第二次遍历删除倒数第 n n n个,但是题目要求如何一次遍历实现,因此使用双指针的办法:让两个指针都指向头部,第一个指针先走 n n n步,然后两个指针一起走,当第一个指针到尾部时,第二个指针刚好指向倒数第 n n n个。具体实施时,需要第二个指针再慢走一步,指向倒数第 n n n个的上一个,这样执行删除操作的时候就可以通过p1.next = p1.next.next;进行删除了

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode p1 = head, p2 = head;
        for (int i = 0; i < n; i++) {
            p2 = p2.next;
        }
        if(p2 == null) return head.next;
        while(p2.next != null) {
            p1 = p1.next;
            p2 = p2.next;
        }
        p1.next = p1.next.next;
        return head;
    }
}

这里存在的一个问题是,如果删除的是头节点,需要进行特殊处理,还有一个巧妙的做法是构建一个 d u m m y dummy dummy节点,让它的下一个指向 h e a d head head,这样就不需要进行特殊处理了。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode p1 = dummy, p2 = dummy;
        for (int i = 0; i < n; i++) {
            p2 = p2.next;
        }
        while(p2.next != null) {
            p1 = p1.next;
            p2 = p2.next;
        }
        p1.next = p1.next.next;
        return dummy.next;
    }
}
复杂度分析
  • 时间复杂度: O ( n ) O(n) O(n)

    一遍遍历复杂度为链表长度 n n n

  • 空间复杂度: O ( 1 ) O(1) O(1)

    需要额外常数个变量空间。

;