双指针(4)

双指针(4)

https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list

栈(递归),双指针都涉及,是道好题。

我的原做法,性能还可以,也达到过100%
主要是用了双倍的指针进度。

双指针(4)
这是原做法的性能,在两方面都可圈可点。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {        
        ListNode* p = head;

        int len = 1;
        while(p && p->next)
        {
            p = p->next->next;
            len+=2;
        }
        if (!p) len--;

        p = head;
        // 目标结点n, bound为n-1
        int bound = len - n;
        
        if (bound == 0)
            return head->next;
            
        for (int i = 1; i < bound; i+=2)
        {
            if (p && p->next && (i+1) != bound)
                p = p->next->next;
            else
                p = p->next;
        }

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

另一种做法,我觉得比我做的想法更妙一点(且更简单一点),使用了相差n的双指针。但是速度和我差不多。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {        
        if(!head -> next) return nullptr;
        ListNode *fast = head;
        ListNode *slow = head;

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

        if(!fast){
            return head->next;    
        }
        
        while(fast -> next){
            fast = fast -> next;
            slow = slow -> next;
        }
        slow -> next = slow -> next -> next;
        return head;
    }
};

最亮眼的是这个做法。是我打算讲的。
这是递归的做法,我觉得性能可能有一点问题。但是偶尔也能过100%。

class Solution {
public:
    int cur = 0;
    ListNode* removeNthFromEnd(ListNode* head, int n) {        
        if(!head) return nullptr;
        head->next = removeNthFromEnd(head->next,n);
        cur++;
        if(n==cur) return head->next;
        return head;
    }
};

这道题应该有可以继续优化的空间。
是第一种还是其他性能更好呢?很明显后两种比较通俗,我发现后两种的性能问题主要在于没有使用第一个fast = fast->next->next技巧。

我把第二种改成了这样:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {        
        if(!head -> next) return nullptr;
        ListNode *fast = head;
        ListNode *slow = head;

        for(int i = 0; i < n;){
            if (fast && fast->next && (i+1) != n)
            {
                fast = fast->next->next;
                i+=2;
            }
            else
            {
                fast = fast->next;
                i++;
            }
        }

        if(!fast){
            return head->next;    
        }
        
        while(fast->next){
            fast = fast->next;
            slow = slow->next;
        }
        slow -> next = slow -> next -> next;
        return head;
    }
};

结果
双指针(4)

性能优化是一辈子的事情。

最后讲一下这个递归方法。

class Solution {
public:
    // 基本情况1: cur == 0
    int cur = 0;
    // 整个归纳步骤:
    ListNode* removeNthFromEnd(ListNode* head, int n) {    
        // 基本情况2: a(1) == nullptr
        // 终止情况2: head == nullptr 
        if(!head) return nullptr;
        head->next = removeNthFromEnd(head->next,n);
        cur++;
        // 基本情况1: b(1) == head->next
        // 终止情况1: cur == n
        if(n==cur) return head->next;
        return head;
    }
};
上一篇:双指针


下一篇:leetcode-环形链表(每日一题)