双指针(4)
https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
栈(递归),双指针都涉及,是道好题。
我的原做法,性能还可以,也达到过100%
主要是用了双倍的指针进度。
这是原做法的性能,在两方面都可圈可点。
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;
}
};
结果
性能优化是一辈子的事情。
最后讲一下这个递归方法。
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;
}
};