【刷题算法】删除链表的倒数第 N 个结点

重新开始刷算法了。记录一下自己对这道算法题的理解,这是力扣第19题:删除链表的倒数第 N 个结点

看到这个题目,首先想到的是,查找到链表的倒数第n个节点,再删除。

一、暴力解法

遍历两次,第一次算出链表长度,然后在遍历倒数第n个。假设总长为N,那么倒数第n个就需要遍历到N-n。

二、双指针法

指针p1从头结点开始,遍历k步,此时再将指针p2指向头结点。p1和p2同时移动,直到p1此时遍历完链表,此时p2指向的就是倒数第k个节点。理解:
假设长度为n,那么p1先走k步,现在p1停在n-k,p2和p1再同步走剩下的,p2就停在(n-k+1)了,也就是倒数第k个。其实就是创造了一个长度为k的滑动窗口,|p2—k—p1|,当p1到了链表末端,p2不就是倒数第k个吗?

三、实现

双指针法不难理解,但是在实际的实现中,我出了好几次错。首先是遍历的条件,第二次遍历选择p1->next来判断是否空指针,还是p2来判断。实际上都可以,但是要知道使用p1来判断,相比使用p1->next,p2会多走一步。
其次,就是一些特殊的测试用例,例如链表只有一个节点,恰好就删除这一个。此时,如果将p1 p2都声明为head,会导致无法删除。通常,这种删除节点的,我觉得还是使用头指针比较好解决,就是一个没有实际含义的指针pre,初始化其next为链表的第一个节点。这样,在最后删除节点时,就算是删除第一个节点也是比较好操作的:
p2->next = p2->next->next; return pre->next;
完整的代码解法:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* pre = new ListNode(0, head);
        ListNode *p1 = head;
        ListNode *p2 = pre;

        for (int i = 0; i < n; i++)
        {
            p1 = p1->next;
        }

        while(p1)
        {
            p1 = p1->next;
            p2 = p2->next;
        }

        if (p2->next)
        {
            p2->next = p2->next->next;
            return pre->next;
        }
        else
        {
            return nullptr;
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值