Java LeetCode每日一题-从易到难带你领略算法的魅力(二十): 删除链表的倒数第 N 个结点

这篇博客介绍了如何删除链表的倒数第n个节点,提供了两种解题思路和对应的Java实现。第一种方法利用栈来辅助操作,第二种方法通过双指针同步前进,避免了两次遍历链表。优化后的解决方案在一次遍历中即可找到并删除目标节点,提高了效率。
摘要由CSDN通过智能技术生成

1.题目要求

  • 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
  • 进阶:你能尝试使用一趟扫描实现吗?

2.题目示例

  • 示例 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]

3.提示

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz
  • Maintain two pointers and update one with a delay of n steps.
    维护两个指针,并以n步的延迟更新一个指针。

4.解题

4.1 解题思路

  1. 读题后最容易想到的是先遍历链表,得到链表的长度L,然后再次遍历链表找到L-n+1就是我们要删除的节点(为了与题中的n同步,节点的下标就从1开始)
  2. 而后为了方便删除数据可以加入哑节点(哑节点是链表中指向第一个有数据节点的节点)。从哑节点开始,遍历到L-n+1的下一个节点就是需要删除的节点(加入哑节点可以避免对头节点的特殊情况做处理)
  3. 在熟悉这个思路的基础上,就可以稍微改良一下思路
  4. 我们可以在遍历链表的同时将所有的节点依次加入栈,栈有先进后出的原则,所以在对栈进行弹出的时候,弹出的第n个节点就是我们要删除的节点,并且当前栈顶的节点就是待删除节点的前驱节点

4.2 业务代码

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        Deque<ListNode> stack = new LinkedList<ListNode>();
        ListNode cur = dummy;
        //放入栈 
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        for (int i = 0; i < n; ++i) {
        	//弹出栈顶部(初始或第一位置)的对象。
            stack.pop();
        }
        //获取栈顶节点
        ListNode prev = stack.peek();
        //删除节点
        prev.next = prev.next.next;
        //去除哑节点
        ListNode ans = dummy.next;
        return ans;
    }
}

4.3 运行结果

结果

5.优化

5.1 优化思路

  1. 换一个思路,由于是要找到倒数第n个节点,我们可以设置两个名为first和second的两个指针,同时对链表进行遍历,并且first要比second快n个节点,这样在first到达最末尾的时候,second正好到达需要删除的节点处
  2. 根据上一个方法的思路,我们可以考虑在开始的时候将second指向哑节点,这样一来当first到达末尾的时候,second到达的是删除节点的前一个节点。

5.2 优化业务代码

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;
        }
        //同时遍历
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        //删除节点
        second.next = second.next.next;
        //删除哑节点
        ListNode ans = dummy.next;
        return ans;
    }
}

5.3 优化结果

结果

6.总结

  • 如果大家有新的想法欢迎在下面留言
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地球村公民

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值