【力扣】19. 删除链表的倒数第 N 个结点

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

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

示例 1:


输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:

输入:head = [1], n = 1
输出:[]
示例 3:

输入:head = [1,2], n = 1
输出:[1]
 

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz


来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

//最先找到的方案:先找到这个链表有多长,然后找到应该移除的节点。
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //先找到这个链表有多长
        ListNode pre = new ListNode(-1,head); //这里pre的作用就是一个哑节点,标识从哪里开始
        int length = 0;
        ListNode cur = head;
        while(cur != null){
            length++;
            cur = cur.next;
        }
        if(length < n){
            return pre.next;
        }
        

        //这里为什么要设置 cur = pre?
        cur = pre;
        //为什么length - n + 1
            //举个例子:我们要length = 5 我们要去掉倒数第二个节点,那么这个节点正数应该是第4个 所以是 5-2+1;
        //其次,我们要找到的正数第四个节点,而是应该找到正数第三个节点
            //所以从1开始,且小于length - n + 1
        for(int i = 1; i< length - n + 1; i++){
            cur = cur.next;
        }
        //当前已经找到cur
        cur.next = cur.next.next;
        return pre.next;
    }

优点:这是最容易想到的方案,劣势也很清楚,遍历了两次

时间复杂度:O(n)

空间复杂度:O(1)

如何将遍历次数减少到一次呢?

那就要借助双指针了:

//第二个方案:使用双指针
        //1.执行一次遍历,找到n在哪个位置 这是第一个指针
        //2.执行第二次遍历,第一个指针指向结束,第二个指针指向当前节点
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //
        ListNode pre = new ListNode(-1,head); //这里pre的作用就是一个哑节点,标识从哪里开始
        
        ListNode first = head; //第一个指针

        //第一次遍历到第n个结束
        for(int i = 1; i<= n; i++){
            first = first.next;
        }
        
        ListNode second = pre; //第二个指针

        //第二次遍历,遍历到第一个指针结束为止
        while(first != null){
            second = second.next;
            first = first.next;
        }
        second.next = second.next.next;
        return pre.next;
    }
一个入行不久的Java开发,越学习越感觉知识太多,自身了解太少,只能不断追寻
原文地址:https://www.cnblogs.com/fengtingxin/p/14757160.html