双向链表删除节点时间复杂度_图解:删除链表倒数第N个节点

前言

在上篇中,小莱给大家分享了链表的相关知识及初步进阶。接下来几期里,小莱计划将链表的相关拓展写成一个系列。

画外音:关于链表相关知识,请点击回顾

今天,我们先来看第一道拓展题。

题目:给定一个链表,删除链表倒数第n个节点,并且返回链表的头结点。

示例:给定一个链表:1->2->3->4->5,和 n = 2。当删除了倒数第二个节点后,链表变为 1->2->3->5。

说明:给定的n保证是有效的。

链表长度法

相信很多人看到这道题时的第一想法都是使用链表长度来进行处理。即先获取链表长度,然后找到指定节点进行删除。

那么我们先来看下这种处理方式。

1、已知链表长度

57c29ca0d4e7c1a1b97d30c41505d43b.png

根据《图解:链表基础知识及反转》中实现的链表结构(如图所示),哨兵节点中的链表长度是已知的,那么删除倒数第N=2节点时就很方便操作了。

ae59766c5fb79f8803094ba9e6eb13e7.png

只需将倒数第3个节点的指针域指向倒数第1个节点即可。这样我们采用一次遍历就可以删除倒数第N个节点了,即找到p节点,操作p->next=p->next->next。

2、未知链表长度

0301199c4a6c82db4b22b15c6a565fcc.png

但是如果是没有存储长度的链表,我们如何来处理呢?

聪明的你可能会说,那还不简单。先扫描一遍链表获取到长度,然后再根据已知链表长度来处理不就行了?

画外音:面试中如果使用了这种方式,那么恭喜你,可以回家等通知了!

显然这样的做法更低效,要遍历两次链表才能完成。

前后指针法

那么有没有更好的方式呢,在未知链表长度情况下,只用一趟就能进行处理(这也正是此题的进阶要求)?

进阶:在链表长度未知情况下,使用一趟扫描实现

如图,我们使用前后指针的方法定义了两个指针变量p和q。其中q为后指针,p为前指针。

d265022b4b6318657c866fc348fd8546.png

f80ce608ee16b9c2f3e6c2455b4f573c.png

bd8b75e3564e1313f2d745fb85431c1f.png

...............

608ec0a2337de8863c40f8f4ac1c1924.png

6e9f48b3e76e6f46b0f342a805359dea.png

初始时,两个指针同时指向哨兵节点。q先向前走n个节点后,p指针从头节点出发,两个指针一起向前遍历。当q.next指向NULL时,p指向倒数第n+1个节点。此时将p->next = p->next->next即可将倒数第N个节点删除。

代码实现:

struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
    int i = 0;
    struct ListNode* p,* q;
    p = q = (struct ListNode*)malloc(sizeof(struct ListNode));
    p->next = head;
    q->next = head;

    while(i<n) {
        q = q -> next;
        i++;
    }

    while(q->next != NULL) {
        q = q -> next;
        p = p -> next;
    }

   if(p -> next == head) {
        return head -> next;
   } else {
        p->next = p->next ->next;
   }

   return head;
}

画外音:代码实现小莱在leetcode亲测!!!

总结

1、在链表长度法里,我们在已知链表长度中虽然根据链表长度只需要进行一次扫描操作即可删除指定节点,但这并不是一种理想方式。

2、未知链表长度情况下,使用前后双指针法进行一趟扫描即可删除指定节点。

关于作者

作者:大家好,我是莱乌,BAT搬砖工一枚。从小公司进入大厂,一路走来收获良多,想将这些经验分享给有需要的人,因此创建了公众号「 IT界农民工」。定时更新,希望能帮助到你。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值