您的位置:首页 > Web前端 > Node.js

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

2020-07-14 05:29 561 查看

19. Remove Nth Node From End of List(删除链表的倒数第N个节点)

  • 3. 一次遍历(One pass algorithm)
  • 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;
    }
    };
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐