算法初学者解决删除链表倒数的节点(力扣19题)(双指针)

1,📚题目介绍

在开始之前请理解下图1

(仅仅在本题的话,链表节点的值不重要,所以我的图省去了值)

题目要求,删除倒数第n个节点。

同时链表至少有一个节点

n在链表节点数之内

2,💡采用方法

这里我采用的是双指针法,至于为什么我也解释不清,先用就行了。

3,🤔具体逻辑

所谓快慢指针,肯定要一个快指针和慢指针了。

定义在哪里呢?先在head节点定义这两位吧。

然后!请集中注意力,争取看一遍就理解.

想删除倒数第一个节点,就必须要找到倒数第二个节点。

想删除倒数第二个节点,就必须要找到倒数第三个节点。

(这是链表删除的知识,如果不懂建议了解一下链表删除操作)

请记住点①:想删除倒数第n个节点,就要找到倒数第n+1个节点。

(你可能想到了极限情况,链表只有一个节点,但先忽略,后面再提)

然后,是让人头疼的问题,单向链表,如何找到最后一个节点?

这不简单吗!循环一下不就行了?这样确实可以,而题目鼓励我们用一次循环就搞定,这里我就用第一次循环的思路。

想找到最后一个节点,最容易想到的方法就是遍历,那就这样做,但是呢,找到最后一个节点的同时顺便把倒数第n+1个节点找到,这样就能删了。

请记住点②:快指针找最后一个节点,慢指针找倒数第n+1个节点

(依据点①,找到倒数第n+1个就可以删除第n个节点)

这时候,你就会神奇的发现,快慢指针的距离,神奇的差了n个节点!

如下图,想删除倒数第2个节点,就让slow与fast差了两个节点,也就是让快指针提前慢指针走2步!

请记住点③:快指针需要提前慢指针n步

综上,想要删除第n个节点就要让先快指针领先慢指针n个节点!

这样似乎就可以写出代码了

  1. 定义快慢指针于head

  2. 让快指针提前走n步

  3. 快慢一起遍历,直到快指针找到了最后一个节点(此时,慢指针就找到了倒数n+1个节点,就能删除倒数第n个节点了!这是题目要求的啊,不要忘记题目的要求)

  4. 删除第n个节点

  5. 返回头结点

但是这样写的话,就会发现是通过不了的。

肯定是遗漏了什么东西,没错,就是极限情况:删除的是链表的头结点,此时模拟一下

按照之前的思路,要删除倒数第n个节点,就要让fast指针领先slow指针一步,由于slow本身就在头结点上,根本找不到头结点前面的节点,这怎么删除呢?

这时候,就要引入传说中的虚拟头结点(dummy head)了,也不要被吓到,这就是一个新的节点,你到时候new ListNode一下就行了,只是他的名字叫虚拟头结点

这个虚拟头结点的一个好处就是方便这种头结点的处理

处理如下图

现在你再看看呢?fast领先慢指针1步,这时fast指针不就是最后一个头结点吗?slow指针不就是倒数第n+1(这个例子中n=1也就是1+1=2)个节点吗?

找到倒数第n+1个(倒数第2个)也就是能正确删除倒数第n(倒数第1个)个节点了。

这就是引入虚拟头结点的好处。

4,⚛️题解

这样本题两个问题,一个主题逻辑和一个极限情况的坑就解决了。

写出如下代码(java):

class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { //定义虚拟头结点用于解决链表只有一个节点的情况 ListNode dummyHead=new ListNode(); //保存头节点 dummyHead.next=head; //在dummyhead上定义快慢指针 ListNode fast=dummyHead; ListNode slow=dummyHead; //让快指针领先n步 while(n-->0){ fast=fast.next; } //一起移动,找到最后的节点 while(fast.next!=null){ fast=fast.next; slow=slow.next; } //删除操作 slow.next=slow.next.next; //返回题目要求的头结点 return dummyHead.next; } }

5,🍃尾声

希望本篇能帮到你,本人也是算法初学者,如果有错误请在评论区指出,谢谢!

可以给个赞吗,这会让博主高兴一整天