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

679 阅读4分钟

这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

今天继续在家休假一天,早点来掘金写文章。不过其实以现代的工作协作软件和协作方式,工作日的休假完全脱离工作的可能性很小,虽然名义上是在家休假,实际还是半在岗状态吧。
立秋之后,朋友圈又开始了秋天的第一杯奶茶这个梗,也不知道是从什么时候开始的,不过好像没有所谓的夏天的第一杯奶茶、冬天的第一杯奶茶。
最近经常在今日头条看别人的经营视频,有二手车商、做快餐的、卖烤鸭的,形形色色,各种都有。突然发现,经营一个店,或者自己做一个什么生意,有很多有意思的环节,生意虽小,但是是一个完整的生意,从购置原材料、生产、销售、售后。残酷的是,任何一个环节出错,都会让你生意整体失败,至少是不赚钱。但是如果真的把一个生意完全跑起来,也非常有成就感。这种小个体户的经营跟程序猿的工作完全不一样,程序猿只是公司整个大生意的领域非常狭窄的一环,要把整个生意做成,真的有太多更重要的因素了。不过也如上面所说,任何一个环节的失败都会导致生意整体失败,做好本职工作,也是在帮助整个大生意成功。写了这么多,希望自己也有一天可以有机会真正操盘一个属于自己的整体的小生意,从无到有,从弱到强,应该也是会非常有成就感。

又扯远了,程序猿还是应该先继续精进自己的技能,今天继续来做leetcode的第19题。

题目

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

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

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

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

思路

这题我理解主要是熟悉一下链表的数据结构吧,算法思想上体现的不多。
题目要删除倒数第n个节点,那起始就是要把倒数n+1个节点的next指向倒数第n-1个节点,即倒数第n个节点的next。
打败你的,很有可能是边界的情况,这里考虑2个边界:

  • n = 1
    这时候要删除最后一个节点,把倒数第2个节点的next指向最后1个节点的next,最后1个节点的next是空,不过也不会带来问题。
  • n = len
    这时候删除的是第一个节点,注意方法让我们返回头节点,这种情况下,返回的就是第2个节点了,所以这种情况要特殊处理一下
    那能不能有1中方法可以不用特殊处理情况2呢?
    这个时候我们可以引入1个哑结点dummy,这个节点是新构造出来的,next指向当前的头结点,这时候,因为这个链表的总长度是len+1,就不可能存在情况2了,我们删除节点后,需要返回新的链表的头结点,只要返回dummy的next即可。

哑结点.png 题目的逻辑这下就不难了:

  1. 先构造哑结点dummy,next指向head;
  2. 将链表中的所有节点按照顺序压栈;
  3. 从栈中弹出n个节点;
  4. 再弹出1个节点,next指向next的next;
  5. 返回dummy.next; 当然,这里有个风险,就是把节点都压栈之后,可能会内存溢出,想要省内存,只能先遍历一遍得到长度,然后计算出我们要删除的节点是正数第m个节点,然后再遍历1次把它删除,这样省了内存,却要多遍历1次了,所以只是空间和时间的一个交换取舍而已。

Java版本代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        Stack<ListNode> stack = new Stack<>();
        ListNode now = dummy;
        while (now != null) {
            stack.push(now);
            now = now.next;
        }
        for (int i = 0; i < n; i++) {
            stack.pop();
        }
        ListNode pre = stack.pop();
        pre.next = pre.next.next;
        return dummy.next;
    }
}