双指针法删除链表的倒数第N个节点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

删除链表倒数第N个节点,直观想到的是遍历两次。为了节约运行时间,题目提示了能否遍历一次完成。因而以下做法都只涉及遍历一次链表。对于链表操作,有一个**小技巧**。通常在head前加一个哑元,避免对头节点的特判。

一、问题概要

表述如上
传说门

二、解法

1.vector实现

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        /* 使程序更鲁棒 */
        if(!head)return head;
        if(n <= 0)return head;
        ListNode* dummy = new ListNode();
        dummy -> next = head;
        vector<ListNode*> nodes;
        /* 指针遍历链表 */
        ListNode* path = dummy;
        while(path != nullptr){
            nodes.emplace_back(path);
            path = path -> next;
        }
        int amounts = nodes.size();
        /* 找到要删除节点的前一个结点 */
        if(amounts - 1 - n >= 0){
            nodes[amounts - 1 - n] -> next = nodes[amounts - n] -> next;
        }
      
        return dummy -> next;
    }
};

      时间复杂度O(n)
      空间复杂度O(n)
      n 为链表长度

2. 双指针实现

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        /* 使程序更鲁棒 */
        if(!head)return head;
        if(n <= 0)return head;
        ListNode* dummy = new ListNode();
        dummy -> next = head;
        
        /* 指针遍历链表 */
        ListNode* first = dummy;
        ListNode* second = dummy;
        /* second 节点领先n个节点 */
        /* second 节点到达尾部时,first节点恰好为要删除节点的前一个节点 */
        for(int i = 0;i < n && second -> next != nullptr;i++){
            second = second -> next;
        }
        if(second -> next != nullptr){
            while(second -> next != nullptr){
                first = first -> next;
                second = second -> next;
            }           
        }

        first -> next = first -> next -> next;
        return dummy -> next;
    }
};

      时间复杂度O(n)
      空间复杂度O(1)
      n 为链表长度

总结

    每次写哑元都有一种艺术感。另外双指针法是一种常用的方法,希望你掌握了。


最后,一看三连是个好习惯。欢迎评论区讨论●ω●

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值