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

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

1. 题目描述
题目链接

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。

2. 题目分析
删除链表的的倒数第N个节点,主要有三种方法:

  • 暴力法,既然是倒数第N个节点,那么直接将链表反转,然后找到第N-1个节点,删除第N个节点就OK了,简单暴力,但一般使用暴力破解都是下下策,即在没法保证更优的解决方法时,不管白猫黑猫,能拽老鼠的就是好猫。
  • 两次遍历法,首次遍历链表,计算节点长度listLenth,再次遍历,找到要删除的节点n的前一个节点,即listLenth-n的位置。
  • 一次遍历法:双节点遍历,当第一个节点遍历到n时,第二节点从头结点跟第一个节点一起往右移动,当第一个节点到达尾节点时,第二节点正好停留在要删除节点的前一个节点。

3. 解决思路
主要讲解一下注意事项,即,出题人挖好的坑。

  • 如果链表长度小于n,那么就不需要删除节点;
  • 如果删除的节点是第一个节点(头结点),那么需要特殊处理,而不是直接p.next = p.next.next;
  • 如果删除的节点时最后一个节点(尾节点),那么也需要特殊处理,而不是直接p.next = p.next.next;
    第一点好解决,判断一下统计的链表长度是否小于n就行了,后面两点就比较麻烦,一开始,我总在考虑怎么在while循环的遍历的时候(使用方法三的时候,方法二不存在第二和第三个注意事项)怎么处理这种特殊情况,但一直失败了,查看别人的解决方案后,发现一个非常棒的思路,即在原来的链表前添加一个新的头结点,这样就完全可以忽略第二和第三个注意事项了(上一博客还分析了自定义链表是否需要头结点的优势,现在就忘了,呜呜呜)。

4. 代码实现(java)
方法一,有兴趣的同学自己去玩玩,我没有使用这种方法,所以不贴方法一的源码了。
方法二:耗时16ms

public static ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null || n<1){
            return head;
        }
        ListNode p = head;
        int listLenth = 0;
        while (p != null){
            p = p.next;
            listLenth++;
        }
        //n的长度大于链表长度
        if (listLenth < n){
            return head;
        }
        //删除头结点
        if (listLenth == n){
            return head.next;
        }
        int count=1;
        p = head;
        while (count < (listLenth-n)){
            p = p.next;
            count++;
        }
        p.next = p.next.next;
        return head;
    }

方法三:耗时8ms

public static ListNode removeNthFromEnd1(ListNode head, int n) {
        if (head == null || n<1){
            return head;
        }
        ListNode newHead = new ListNode(-1);//随便给个值,不做使用
        newHead.next = head;
        ListNode first = newHead.next;
        ListNode second = newHead;
        int count = 0;
        while (first != null){
            first = first.next;
            count++;
            if (count > n){
                second = second.next;
            }
        }
        if(count < n){
            return head;
        }

        second.next = second.next.next;
        return newHead.next;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值