LeetCode 19.Remove Nth Node From End of List

本文探讨了在单链表中删除倒数第N个节点的问题,提供了两次遍历和一次遍历的解决方案。首次尝试存在缺陷,第二次通过增加头结点解决了问题,实现了两次遍历。最后,介绍了一次遍历的官方解法,利用双指针技巧,高效地完成了任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given a linked list, remove the n-th node from the end of list and return its head.

Example:

Given linked list: 1->2->3->4->5, and n = 2.

After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:

Given n will always be valid.

Follow up:

Could you do this in one pass?

第一次错误代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        int l=0;
        ListNode* p=head;
        while(p)
        {
            l++;
            p=p->next;
        }
        int index=1;
        p=head;
        while(p)//当删除第一个节点时无法实现
        {
            if(index==l-n)
            p->next=p->next->next;
            p=p->next;
            index++;
        }
        return head;
    }
};

第二次通过代码

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        int l=0;
        ListNode* p=head;
        while(p)
        {
            l++;
            p=p->next;
        }
        ListNode* ans=new ListNode(0);//建立头结点,与head链接起来
        int index=0;//index现表示头结点的下标
        ans->next=head;
        p=ans;
        while(index!=l-n)
        {
            p=p->next;
            index++;                
        }//找到待删除结点的前一个结点p
        p->next=p->next->next;//删除该节点
        return ans->next;
    }
};

如果结果可能为空,应该加个头结点,然后返回头结点的next。此方法是两次遍历,先找到链表长度,再遍历删除,遍历操作执行了2L-n步。
题目说Could you do this in one pass?
好的,来看看官方一次遍历解法

我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1步,而第二个指针将从列表的开头出发。现在,这两个指针被 n 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 n 个结点。我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* ans=new ListNode(0);
        ans->next=head;
        ListNode* p,*q;
        p=ans;
        q=ans;
        int pt,qt;
        pt=0;
        qt=0;
        while(q)//q为空即指向尾结点的next
        {
            if(qt-pt<=n)//p,q中结点个数小于n,p向后移动,q保持不变
            {
                q=q->next;
                qt++;
            }
            else//p,q同时向后移
            {
                p=p->next;
                q=q->next;
                pt++;
                qt++;                
            }

        }
        //删除q后面的结点
        p->next=p->next->next;
        return ans->next;
    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值