19. Remove Nth Node From End of List(删除链表的倒数第N个节点)两种解法(C++ & 注释)

1. 题目描述

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

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:
给定的 n 保证是有效的。

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

题目链接:中文题目英文题目

2. 两次遍历(Two pass algorithm)

2.1 解题思路

比较常规的思路是,先一次遍历链链表,统计一共有多少个节点,然后删除第(总结点数 - n + 1)个节点就行了,这是一种从前往后删除节点的思路,需要遍历链表两次。

这个思路的代码大家可以自己想想怎么写,如果不是很清楚可以参考下面3. 一次遍历的代码,大体的思路和删除节点的思路都是大同小异的。

3. 一次遍历(One pass algorithm)

3.1 解题思路

那么,根据上面的2. 两次遍历的思路,我们反过来考虑一下,能否从后往前删除节点了,这样就只需要遍历一次链表。首先,我们不知道给定链表一共有多少个节点,所以先找到最末节点与被删除节点之间的距离:n - 1,即删除节点移动多少,达到末尾节点。在查找被删除节点的过程中,这个距离是相对固定的,比如下面这个例子:

1 -> 2 -> 3 -> 4 -> 5, n = 3

开始,被删除节点(deletedNode)指向1,末尾节点(endOfLink)指向n - 1 = 2,即3这个节点,但这个末尾节点不是真正的末尾节点,我们知道真正的末尾节点是5,所以我们需要循环找到真正的末尾节点,所以每移动末尾节点一次,我们相应移动被删除节点一次。同样,我们在开始初始化一个前节点(pre) = nullptr,后节点(next) = 2,这两个节点也跟随末尾节点移动而移动。

所以被删除节点(deletedNode) = head, 末尾节点(endOfLink) = head,前节点(pre) = nullptr,后节点(next)= head->next。如果deletedNode 等于head,直接返回head->next;反之,pre->next = next,返回head即可。

大家可以参考一下下图的思路,加深理解:
在这里插入图片描述

3.2 实例代码

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // if (!head) return nullptr; // 通过测试,题目不需要考虑空链表的情形
        ListNode* endOfLink = head, * deletedNode = head, * pre = nullptr, *next = head->next;
        for (int i = 0; i < n - 1; i++) endOfLink = endOfLink->next; // 固定需要删除节点与末尾节点的距离

        // 一次遍历找到需要删除的节点
        while (endOfLink->next) {
            endOfLink = endOfLink->next;
            deletedNode = deletedNode->next;
            if (pre) pre = pre->next;
            else pre = head; // 因为首次pre为空指针,需要重新赋值
            next = next->next;
        }

        if (deletedNode == head) return head->next; // 如果需要删除的节点为head,直接返回head的下一个节点即可
        pre->next = next;
        return head;
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值