力扣Hot100-19删除链表倒数第N个节点【双指针】【递归】

力扣Hot100-19 删除链表倒数第N个节点

全部刷题与学习记录

【C++刷题学习笔记目录】

原题目

题目地址:19. 删除链表的倒数第 N 个结点

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

**进阶:**你能尝试使用一趟扫描实现吗?

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

考查知识点

双指针、递归

自己的第一遍解法

直观的想法就是扫描两遍,第一遍计算链表长度size,第二遍找到倒数第n+1个节点,也就是正数size-n-1处的节点,然后更改指向,越过要删除的节点

//扫描两遍,一遍确定链表长度,第二遍删除节点
class SolutionScan2 {
    
    
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
    
    
        if (head == nullptr)    return nullptr;

        //统计链表大小
        int size = 0;
        ListNode* curNode = head;
        while (curNode != nullptr) {
    
    
            size++;
            curNode = curNode->next;
        }

        //找到倒数第n也就是正数size-n-1个节点,特例头结点
        if (size == n)  return head->next;

        curNode = head;
        int i = 1;
        while (curNode != nullptr && i <= size - n - 1) {
    
    
            curNode = curNode->next;
            i++;
        }

        //删除该节点
        curNode->next = curNode->next->next;
        return head;
    }
};

好的解法

题目中说最好是只扫描一遍,链表和数组类题目,一般都离不开双指针,尤其是链表的特殊性,还能够用递归来解。这里参考了公众号【数据结构与算法】的双指针和递归解法

使用双指针和递归就能做到只扫描一遍

双指针

倒数第n+1个节点和尾节点的距离一定是n,那么只要维护两个指针fastslow,让他们之间距离是n,只要fast指向尾节点了,slow指向的必然就是倒数第n+1个节点

//双指针法,两指针先保持n的距离,fast指向尾节点的时候,slow指向的就是要删除节点的前一节点
class Solution_douPtr {
    
    
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
    
    
        if (head == nullptr) return nullptr;

        ListNode* fast = head;
        ListNode* slow = head;

        //fast移动n步与slow拉开距离
        for (int i = 0; i < n; ++i) {
    
    
            fast = fast->next;
        }
        //fas为空节点,说明移动了list.size步,要删除的是头结点
        if (fast == nullptr)    return head->next;

        //保持slow与fast间距同时移动,直到slow指向要删除节点的前一节点
        while (fast->next != nullptr) {
    
    
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;

        return head;
    }
};

递归

递归的方法就是直接从尾节点开始计算长度,当计算到倒数第n+1个节点的时候,就可以了

//递归
class Solution {
    
    
private:
    //从尾节点开始倒数长度,直到找到倒数n+1节点
    int length(ListNode* node, int n) {
    
    
        if (node == nullptr)
            return 0;

        int pos = length(node->next, n) + 1;
        if (pos == n + 1)
            node->next = node->next->next;

        return pos;
    }
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
    
    
        int pos = length(head, n);
        if (pos == n)
            return head->next;
        return head;
    }
};

Guess you like

Origin blog.csdn.net/weixin_44484715/article/details/115689841