Loading

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

1.问题描述

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

示例

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

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

说明

给定的 n 保证是有效的。

进阶

你能尝试使用一趟扫描实现吗?

2.求解

两次遍历

​ 对于本题,我们并不知道列表的节点数目,我们可以先遍历一遍,拿到节点数length,然后第二次再遍历至length - n的位置,这个位置就是倒数第n个的前一个位置,此时我们让它的next=next.next即可完成目标。

代码如下
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        int length = 0;
        ListNode first = head;
        while (first != null) {
            first = first.next;
            length++;
        }
        length = length - n;
        first = dummy;
        while (length > 0) {
            length--;
            first = first.next;
        }
        first.next = first.next.next;
        return dummy.next;
    }
  • 时间复杂度O(n),n为数组长度。
  • 空间复杂度O(1),只使用了常数级的额外空间

ps: 一开始的时候设置头指针时候直接使用dummy指向head,然后发现遇到需要删除头部指针时或者只有一个节点时,处理比较麻烦,这里需要注意的是,如果遍历输出带头节点的单链表,带头结点的判断条件是while(head->next!=NULL)

双指针一次遍历

  • 在本题中可以使用双指针,先设置哑节点,定义指针p,和哨兵指针q,通过让哨兵指针先行n+1步(有哑节点存在),让两指针之间保持不变的距离。
  • 遍历哨兵指针,同时移动指针p,这样当哨兵指针移动至链表结尾时,指针q所指向的节点即时倒数第n+1个节点,此时令该节点的next指向next.next即可完成目标
代码如下
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode l1 = dummy;
        ListNode l2 = dummy;
        while (n >= 0){
            n--;
            l2 = l2.next;
        }
        while(l2 != null){
            l1 = l1.next;
            l2 = l2.next;
        }
        l1.next = l1.next.next;
        return dummy.next;
    }
  • 时间复杂度、空间复杂度不变

ps:这里需要注意的是,虽然使用两个指针只进行了一次遍历,但性能却不会提升,也可以使用哈希结构把整个节点存储下来,然后进行删除操作,但是我试了下,速度并没有很快。

递归

​ 本题中的递归比较容易理解,递、归的脉络比较清晰。

  1. 首先是递的过程,定义递归函数,每次将当前节点的下个节点传入,判断当前节点是否为null,若为null即到达临界条件。
  2. 到达临界条件即,节点遍历完成,开始归来的过程,归来时每次令计数器加一,判断计数器是否等于n,若等于n,则说明咋已经找到第n的节点的前一个节点(计数器从0开始),此时可令该节点的next指向next.next。
  3. 需要注意的一点是,如果删除的是头节点时,此时会在调用递归函数最后返回的值是n,我们还需要最后判断下返回值是否等于n,若等于,则将头节点的next指针置空
代码如下
    /*
    执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
    内存消耗:36.2 MB, 在所有 Java 提交中击败了79.58% 的用户
    */
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int index = access(head, n);
        if(index == n - 1){
            head = head.next;
        }
        return head;
    }

    int access(ListNode listNode, int n){
        if(listNode.next == null){
            return 0;
        }
        int index = access(listNode.next, n);
        if(index == n - 1){
            listNode.next = listNode.next.next;
        }
        return ++index;
    }
posted @ 2020-10-06 17:03  水纸杯  阅读(145)  评论(0)    收藏  举报