LeetCode 链表专题 19 删除倒数第n个数 java 递归解法&&多指针解法

题目详情

本题是删除链表的倒数第n个数,因为链表的性质,所以必须得遍历才知道链表有多长。
为了知道每个节点是倒数第几个节点,我们这里用回溯来计数,从而统计自己是第几个数。
另外我们删除第n个数的逻辑是,用第n+1个数去指向n-1个数(倒数)。
不过这存在一个特殊情况。n-1的数必然存在,它可以为空,但n+1的数可能不存在,当我们要删除的数就在链表的头部时,n+1这个元素为空,我们可以用一个节点指向空,但绝不能用空节点指向另外一个节点。
所以我们需要去判断第n个元素是否是头节点,如果是,那么我们就返回头结点的next即可。
代码的效果是100%和99.19%

递归解法

这是我一个月前做的了,用的回溯思想,找到n-1和n+1的那个点。
其中也就一个特殊情况。

class Solution {
    private boolean flag = false;// 用以强制退出递归
    ListNode nSubOne = null,nPlusOne = null,nn=null;
    public ListNode removeNthFromEnd(ListNode head, int n) {
        backtrack(head,n);
        //只需要考虑一个特殊情况:删除的是头元素,则无法用n+1->n-1来删除n,那么直接返回head的next即可
        if(nn==head)
            return head.next;
        nPlusOne.next = nSubOne;
        return head;
    }
    public int backtrack(ListNode p, int n){
        if(flag)
            return 0;
        //判断是否为空
        if(p==null)
            return 0;
        int count = backtrack(p.next,n);
        count++;
        //进行判断,找到倒数n-1,n和n+1个数
        if(count==n-1)
            nSubOne = p;
        else if(count==n+1){
            nPlusOne = p;
            flag = true;
        }
        else if(count==n)
           nn = p;
        return count;
    }
}

多指针解法

一个多月后再做此题,回溯忘的一干二净,第一反应是多指针。
总共三个指针,一个preN,一个nextN,一个tail。
tail领先preN一共n次next(也就是中间隔了n-1个点),而nextN领先了preN两次next(也就是一个点)。
当三个指针同时往后跑,tail.next为空时便说明走到链表尾了。而此时preN刚好走到倒数第n个点的前面,nextN刚好走到倒数第n个点的后面。此时preN.net = nextN即可。
这里和上面一样,有特殊情况,当n=链表长度时,也就是tail先跑了之后next为空,则直接返回head.next即可。
看代码:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //没有什么记忆了,感觉还是得多刷题,不然这种做过的题都没什么记忆,用什么方法还得想半天,其实很不应该
        //需要考虑的是,这个是个链表,你只能一直访问下去
        //需要找到第倒数第n个节点,
        //只用一趟就解决
        //因为n有效,所以我直接把第一个节点往后走n个,领先n,然后两个一起往后走
        //这样的话,当领先的为null时,那么就能找到第n个了
        //这里因为是要删除,所以,还得搞一个近的
        //所以是n-1是n+1,总共三个指针
        if(n==0){
            return head;
        }
        ListNode ans=head, preN=head, nextN=head, tail=head;
        //当链表长度等于n时,需要考虑,其他都不存在问题
        
        for(int i=0; i<n; i++){
            tail = tail.next;
        }
        if(tail==null){//n=链表长度
            return head.next;
        }
        
        nextN = nextN.next.next;

        while(tail.next!=null){
            tail=tail.next;
            preN = preN.next;
            nextN = nextN.next;
        }
        preN.next = nextN;
        return head;
    }
}

时间复杂度都是一样的,都是O(n),没啥区别,空间复杂度也是O(1),比上面的常数项略多。
只是一个不同的思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值