力扣19:删除链表的倒数第N个结点

力扣19:删除链表的倒数第N个结点

题目描述

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

在这里插入图片描述

输入输出样式

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
输入:head = [1], n = 1
输出:[]
输入:head = [1,2], n = 1
输出:[1]

解法一常规思路(双指针的思路)

  1. 新建链表的各个结点

  2. 遍历查找链表中包含结点的个数

  3. 找出要寻找的结点对应在链表中的位数

  4. 对该结点的前驱和后继进行操作

  5. 但是这种算法,力扣在执行的时候会有问题,特别是链表结点个数为[1],输出要删除倒数最后一个结点的值的时候,会在在执行过程中有问题,但在自己编译器中能完美执行

    #include<iostream>
    #include<vector>
    
    using namespace std;
    
    typedef struct ListNode * LNode;
    
    struct ListNode
    {
        int val;
        LNode next;  
    
        //初始化
        ListNode():val(0),next(nullptr){};
        ListNode(int x):val(x),next(nullptr){};
        ListNode(int x,ListNode *next):val(x),next(next){};
    };
    
    void createListNode(LNode Nlist)
    {
        LNode plist,qlist;
        plist=Nlist;
        int num;
        //输入将要创建结点的个数
        cin>>num;
        for(int i=0;i<num;i++)
        {
            qlist=new ListNode();
            cin>>qlist->val;
            qlist->next=nullptr;
            //使用尾插法衔接新插入的结点
            plist->next=qlist;
            plist=qlist;
        }
    }
    
    void printListNode(LNode Nlist)
    {
        LNode plist;
        //跳过链表的头结点
        plist=Nlist->next;
        while(plist)
        {   
            cout<<plist->val<<" ";
            plist=plist->next;
        }
        cout<<endl;
    }
    
    
    int travelListNum(ListNode * Nlist)
    {
        ListNode * plist;
        int totalNum=0;
        plist=Nlist->next;
        while(plist)
        {
            totalNum++;
            plist=plist->next;
        }
        return totalNum;
    }
    
    
    ListNode *removeNthFromEnd(ListNode *head,int n)
    {
        int totalNum=travelListNum(head);
        //当要删除的倒数值小于1时,跳出
        if(n<1)
        {
            return head;
        }
        int tempNum=totalNum-n+1;
    
        //tlist指向前驱结点
        //plist指向当前结点 
        ListNode *tlist;
        ListNode *plist;
        int currentIndex=0;
        tlist=head;
        plist=head->next;
        //找到当前结点的前面那个结点
        while(currentIndex+1<tempNum)
        {   
            tlist=tlist->next;
            plist=plist->next;
            currentIndex++;
        }
        if(plist)
        {   
            if(plist->next==nullptr)
            {
                tlist->next=nullptr;
            }
            else{
                tlist->next=plist->next;
            }
        }
        return head;
    }
    
    
    int main()
    {
        //建立链表,并分配指针
        LNode Nlist=new ListNode();
        createListNode(Nlist);
        printListNode(Nlist);
        travelListNum(Nlist);
        int deleteIndex;
        cout<<"please input which index you want to delete"<<endl;
        cin>>deleteIndex;
    
        removeNthFromEnd(Nlist,deleteIndex);
        printListNode(Nlist);
    }
    

    解法二计算链表长度

    通过看解析,发现,对于连链表进行操作时,常用的技巧就是添加一个哑结点,使用他的next指针指向链表的头节点,此时就不需要对链表的头结点进行特殊判断。

    int travelListNum2(ListNode * Nlist)
    {
        ListNode * plist;
        int totalNum=0;
        plist=Nlist;
        while(plist)
        {
            totalNum++;
            plist=plist->next;
        }
        return totalNum;
    }
    
    ListNode *removeNthFromEnd2(ListNode *head,int n)
    {
        int totalNum=travelListNum2(head);
        if(n<1)
        {
            return head;
        }
        int tempNum=totalNum-n+1;
        //新建哑结点,并直线跟原来的头节点
        ListNode *dummy=new ListNode(0,head);
        ListNode *cur=dummy;
        for(int i=1;i<totalNum-n+1;i++)
        {
            cur=cur->next;
        }
        cur->next=cur->next->next;
        ListNode * ans=dummy->next;
        delete dummy;
        return ans;
    }
    

    方法3使用堆栈的方法

    //使用堆栈完成,因为时逆序的
    ListNode *removeNthFromEnd3(ListNode *head,int n)
    {
        ListNode*dummy=new ListNode(0,head);
        stack<ListNode*>stk;
        ListNode* cur=dummy;
        //将指针推入堆栈
        while(cur)
        {
            stk.push(cur);
            cur=cur->next;
        }
        for(int i=0;i<n;i++)
        {
            //出栈第n个指针
            stk.pop();
        }
        //倒数第n+1个指针在堆栈顶部
        ListNode *pre=stk.top();
        pre->next=pre->next->next;
        ListNode*ans=dummy->next;
        delete dummy;
        return ans;
    }
    

    方法4使用快慢指针的方法

    //使用快慢指针的方法
    ListNode *removeNthFromEnd4(ListNode *head,int n)
    {
        ListNode *dummy=new ListNode(0,head);
        ListNode *fast=dummy;
        ListNode *slow=dummy;
    
        //fast要比slow超前n个位置
        for(int i=0;i<n+1;i++)
        {
            fast=fast->next;
        }
    
        //以fast的指向作为判断基准
        while(fast)
        {   
            fast=fast->next;
            slow=slow->next;
        }
    
        //删除slow的下一个值
        slow->next=slow->next->next;
        ListNode *ans=dummy->next;
        delete dummy;
        return ans;
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值