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

497 阅读2分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。

题目:给定一个链表,删除此链表的倒数第N个节点,之后返回链表的头节点。

解题思路

由题可知,其最终的返回结果是删除节点之后的链表的头节点,如果按照常规思路,则需要判断当前删除节点是否为头节点,并且根据是和否做两种判断,代码逻辑会显得较为混乱,此处可以新增一个头节点,将给定的链表作为新创建的头结点的next,之后删除的逻辑就相对而言较为简单,删除之后返回头节点的next即可,代码如下:

public static ListNode removeNthFromEnd(ListNode head, int n) {
        int len =0;
        ListNode cur = head;
        ListNode headpoint = new ListNode(0, head);
        ListNode temp = headpoint;
        while(cur!=null){
            len++;
            cur = cur.next;
        }
        for(int i=1;i<len-n+1;i++){
            temp = temp.next;
        }
        temp.next = temp.next.next;
        return headpoint.next;
    }

此方式获得的是删除节点的前一个节点,之后根据简单的链表删除逻辑即可得到最终结果,其时间复杂度为O(N)O(N),空间复杂度为O(1)O(1)。LeetCode的结果显示超过100%。但此题是扫描了两次链表得到的结果,题目的进阶要求为是否可以只扫描一次得到结果,如何实现?

进阶解法(只扫描一遍链表)

另一种思路是依然事先创建一个空的头节点,之后next指向head,依次遍历链表,将链表元素入栈(利用栈先进后出的特性,链表的倒数第n个节点即为第n个出栈的元素),之后将要删除的元素出栈得到栈顶元素即可,根据链表删除的特性可以很简单得到结果,代码如下:

public static ListNode removeNthFromEnd2(ListNode head, int n) {
        ListNode headpoint = new ListNode(0, head);
        ListNode cur = headpoint;
        Stack<ListNode> s = new Stack<>();
        while (cur!=null){
            s.push(cur);
            cur = cur.next;
        }
        for(int i=0;i<n;i++){
            s.pop();
        }
        ListNode peak = s.peek();
        peak.next = peak.next.next;
        return headpoint.next;
    }

此方法的时间复杂度为O(N)O(N),空间复杂度为O(N)O(N)

快慢指针

另一种更巧妙的方法是使用双指针来解,若要删除链表倒数第n个节点,只需要首先设置快慢指针,使得快慢指针的相距间隔为n即可,之后分别移动快慢指针,使得快指针为空,之后慢指针指向的就是待删除元素的前一个结点,根据链表删除规则即可完美删除,代码如下:

public static ListNode removeNthFromEnd3(ListNode head, int n) {
        ListNode headpoint = new ListNode(0, head);
        ListNode low = headpoint;
        ListNode fast = head;
        for(int i=0;i<n;i++){
            fast = fast.next;
        }
        while (fast!=null){
            fast = fast.next;
            low = low.next;
        }
        low.next = low.next.next;
        return headpoint.next;
    }

上述方法的时间复杂度仍然是O(N)O(N), 因为只使用了常数个变量,因此空间复杂度为O(1)O(1)