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

如果我们要删除节点 y,我们需要知道节点 y 的前驱节点 x,并将 x 的指针指向 y 的后继节点
但由于头节点不存在前驱节点,因此我们需要在删除头节点时进行特殊判断。但如果我们添加了哑节点,那么头节点的前驱节点就是哑节点本身,此时我们就只需要考虑通用的情况即可。
两种方法:

1.计算长度L,用L-n+1得到正方向这个位置,删掉

/**
* 获得本链表的长度
* @return
* @date 2016-9-28
* @author shaobn
*/
public int getLength(){
int length = 0;
Node tmpNode = this.headNode;
while(tmpNode!=null){
length++;
tmpNode = tmpNode.next;
}
return length;

}

}

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //初始化空节点
        //将head链表加入,这样就算是头节点也可以遍历到
        ListNode dummy = new ListNode(0, head);
        int length = getLength(head);
        ListNode cur = dummy;
        //head的头节点在index 1 的位置
        //length - n + 1表示倒数第n位在正数第几位
        for(int i = 1; i < length - n + 1; ++i){
            cur = cur.next;

        }
        cur.next = cur.next.next;
        //dummy.next就是把头去掉了,最开始的0,还原成原本的链表
        ListNode ans = dummy.next;
        return ans;

    }
    //获取链表长度
    //public int length!!!不是public void length!!!注意
    public int getLength(ListNode head){
        int length = 0;
        while(head != null){
            ++length;
            head = head.next;
        }
        return length;

    }

}

复杂度分析

时间复杂度:O(L),其中 L 是链表的长度。

空间复杂度:O(1)。

2.快慢指针

思路与算法

我们也可以在不预处理出链表的长度,以及使用常数空间的前提下解决本题。

由于我们需要找到倒数第 n 个节点,因此我们可以使用两个指针 first 和 second 同时对链表进行遍历,并且 first 比 second 超前 n 个节点。当first 遍历到链表的末尾时,second 就恰好处于倒数第 n个节点。

具体地,初始时first 和 second 均指向头节点。我们首先使用first 对链表进行遍历,遍历的次数为 n。此时,first 和 second 之间间隔了 n−1 个节点,即 first 比 second 超前了 n 个节点。

在这之后,我们同时使用first 和 second 对链表进行遍历。当first 遍历到链表的末尾(即 first 为空指针)时,second 恰好指向倒数第 n个节点。

根据方法一,如果我们能够得到的是倒数第 n 个节点的前驱节点而不是倒数第 n 个节点的话,删除操作会更加方便。因此我们可以考虑在初始时将second 指向哑节点,其余的操作步骤不变。这样一来,当first 遍历到链表的末尾时,second 的下一个节点就是我们需要删除的节点。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
       ListNode dummy = new ListNode(0, head);
       ListNode first = head;
       ListNode second = dummy;
       //让first先走n位
       for(int i = 0; i < n; ++i){
           first = first.next;
       }
       //当first先走n位之后,first和second一起走
       //first != null,也就是first走到最后的时候,second正好走到倒数第n位,引起dummy前加了一个0,所以second正好走到了倒数第n位的前置
       while( first != null){
           first = first.next;
           second = second.next;
       }
       //把second的next删掉
       second.next = second.next.next;
       ListNode ans = dummy.next;
       return ans;
    }

}

复杂度分析

时间复杂度:O(L),其中 L 是链表的长度。

空间复杂度:O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值