leetcode 19. 删除链表的倒数第 N 个结点

19. 删除链表的倒数第 N 个结点


题目


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

在这里插入图片描述

示例 1:

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

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

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

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

1、快慢指针


这题做烂了,快指针先走n步,然后快慢一起走到最后一个节点fast.next != None(注意不是走到空!不然slow会指向待删除结点),则最后slow会指向待删除结点的前驱,就可以删了
在这里插入图片描述

注意点:链表删除问题,加头结点哈


时间复杂度: O ( L ) O(L) O(L)

空间复杂度: O ( 1 ) O(1) O(1)


python


class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummyHead = ListNode()
        dummyHead.next = head
        slow, fast = dummyHead, dummyHead
        while n != 0:
            fast = fast.next
            n -= 1
        while fast.next != None : # 让slow最终指向待删除结点的前一个结点
            slow = slow.next
            fast = fast.next
        slow.next = slow.next.next
        return dummyHead.next

c++


class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 注意slow最终指向的是代数第n个结点的前驱!!
        if(head == NULL || head->next == NULL)
            return head;
        ListNode* dummyNode = new ListNode(-1);
        dummyNode->next = head;
        ListNode* slow = dummyNode; 
        ListNode* fast = dummyNode;
        while(n-- != 0)  //移动n次
            fast = fast->next;
        while(fast->next && slow->next){
            slow = slow->next;
            fast = fast->next;
        }
        slow->next = slow->next->next;
        return dummyNode->next;
    }
};

一种错误写法


典型错误哈,当链表只有一个元素[1]经过内层while,fast已经指向1,再经过slow = slow.next;fast = fast.next, fast = None了,但是却处于最外层while的内部,而最外层条件是fast.next != None,明显不符合,最后slow指向1,也表明这么做是错误的。因此必须老老实实分两步写

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummyHead = ListNode()
        dummyHead.next = head
        slow, fast = dummyHead, dummyHead
        while fast.next != None : # 让slow最终指向待删除结点的前一个结点
            while n != 0:
                fast = fast.next
                n -= 1
            slow = slow.next
            fast = fast.next
        slow.next = slow.next.next
        return dummyHead.next

2、递归:c++


方法是leetcode 203/王道01,02【链表递归删除操作】有两种递归写法

注意:n都要作为引用传入!


时间复杂度: O ( L ) O(L) O(L)

空间复杂度: O ( L ) O(L) O(L)


2.1 无返回值递归写法:删除工作手动进行


这里改成了带头结点的做法,不带头结点就把所有的dummyNode->next换成head即可

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 注意slow最终指向的是代数第n个结点的前驱!!
        if(head == NULL || head->next == NULL)
            return head;
        ListNode* dummyNode = new ListNode(-1);
        dummyNode->next = head;
        func(dummyNode, n);
        return dummyNode->next;
     
    }

    void func(ListNode* dummyNode, int &n){
        //递归到最后,再机算弹出次数,仍然是链表递归的问题
        if(dummyNode->next == NULL)
            return ;
        func(dummyNode->next, n);
        n -= 1; // 形参内传入n的引用,才是在原n不断-1;比如n=2,则2-1=1,然后1-1 = 0;如果不传引用,每次都是在2-1;2-1;2-1;也就是不是引用的话相当于创建了n的副本
        if(n == 0)
            dummyNode->next = dummyNode->next->next;
            return ;
    }
};

2.2 有返回值写法:制定连接规则


class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 注意slow最终指向的是代数第n个结点的前驱!!
        return func(head, n);

     
    }
    ListNode* func(ListNode* head, int &n){
        /**栈弹出过程
        func(5)
            5->next = func(NULL) = NULL
            2-1 = 1     retrun 5->NULL
        func(4)
            4->next = func(5) = 5->NULL
            1-1 = 0     return 4->next = 5->NULL
        func(3)
            3->next = func(4) = 5->NULL
            return 3->5->NULL
        。。。。。
        **/
        if(head == NULL)
            return head;
        //先递归到最尾部
        head->next = func(head->next, n);
        n -= 1;
        if(n==0) //当前结点head要删除,则返回head->next作为下一次head->next的连接内容
            return head->next;
        return head; //正常的每次连接方式
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunMoonStar_c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值