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

题目链接

https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

题解

题解一(Java)

作者:@仲景
最简单的方法就是先遍历一遍链表,统计出链表的长度,求出倒数第n的所在的正数位置
这个方法需要两次遍历,时间复杂度的常数项会大一些,空间复杂度O(1)

class Solution {

    public ListNode removeNthFromEnd(ListNode head, int n) {

        // 创建一个新头,链到链表的头部
        ListNode newHead = new ListNode(-1, head);

        // 计算链表一共有多少个节点
        ListNode node = head;
        int count = 0;
        while (node != null) {
            count++;
            node = node.next;
        }

        // 得到倒数第n个是正数第几个节点
        count = count - n + 1;

        // 得到倒数第n个节点的前一个节点
        node = newHead;
        while (count-- > 1) {
            node = node.next;
        }

        // 删除节点
        node.next = node.next.next;


        return newHead.next;
    }
}

题解二(Java)

作者:@仲景
说到倒数,其实可以想到用栈来解决,因为栈是FILO的结构,所以所有节点压入栈后,其实就是在倒数
这个方法,时间复杂度和题解一基本一样,虽然遍历链表是一次遍历,但是弹栈也算在内的话,和题解一是一样的。
并且需要一个辅助栈,所以空间复杂度是O(n)

class Solution {

    public ListNode removeNthFromEnd(ListNode head, int n) {

        // 创建一个新头(如果删除的是头结点的话需要一个虚拟节点来表示头结点的前一个节点)
        ListNode newHead = new ListNode(-1, head);

        // 创建一个辅助栈
        LinkedList<ListNode> stack = new LinkedList<ListNode>();

        // 遍历链表
        ListNode node = newHead;
        while (node != null) {
            stack.push(node);
            node = node.next;
        }

        // 弹栈,一直弹到倒数第n个节点的前一个节点
        while (n-- >= 0) {
            node = stack.pop();
        }

        // 删除节点
        node.next = node.next.next;

        return newHead.next;
    }
}

题解三(Java)

作者:@仲景
使用双指针可以保证绝对只遍历一次链表就可以找到倒数第n个节点的前一个节点
需要注意的是单链表删除某个节点需要找到该节点的前一个节点,所以其实左右指针相差的步数是n+1

class Solution {

    public ListNode removeNthFromEnd(ListNode head, int n) {

        // 创建一个新头(如果删除的是头结点的话需要一个虚拟节点来表示头结点的前一个节点)
        ListNode newHead = new ListNode(-1, head);

        ListNode left = newHead;
        ListNode right = newHead;

        // 右指针向右移动n次,然后左右指针一同移动时,右指针越界,左指针指向倒数第n个节点
        // 因为要删除左指针所在节点,所以右指针要多走一步
        // 其实左右指针相差的应该是n+1步
        while (n-- >= 0) {
            right = right.next;
        }

        // 左右指针同时移动,直到右指针越界
        while (right != null) {
            left = left.next;
            right = right.next;
        }

        // 此时左指针指向要删除节点的前一个节点
        left.next = left.next.next;

        return newHead.next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值