方法一:双指针遍历两遍
1.1:没有dummy node版本
时间复杂度:O(n)
空间复杂度:O(1)
class Solution
{
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
int size = 0;
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr != nullptr)
{
curr = curr->next;
size++;
}
curr = head;
if (size==n)
{
head = head->next;
delete curr;
return head;
}
for (int i = 0; i < size - n; i++)
{
prev = curr;
curr = curr->next;
}
prev->next = curr->next;
delete curr;
return head;
}
};
1.2:使用dummy node
可以简化删除头节点的操作
时间复杂度:O(n)
空间复杂度:O(1)
class Solution
{
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
int size = 0;
ListNode* dummy = new ListNode(-1, head);
ListNode* prev = dummy;
ListNode* curr = head;
while (curr != nullptr)
{
curr = curr->next;
size++;
}
curr = head;
for (int i = 0; i < size - n; i++)
{
prev = curr;
curr = curr->next;
}
prev->next = curr->next;
delete curr;
return dummy->next;
}
};
方法二:栈
时间复杂度:O(n)
空间复杂度:O(n)
class Solution
{
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
stack<ListNode*> stk;
ListNode* dummy = new ListNode(-1, head);
ListNode* prev;
ListNode* curr;
for (ListNode* temp = dummy; temp != nullptr; temp = temp->next)
{
stk.push(temp);
}
for (int i = 0; i < n; i++)
{
curr = stk.top();
stk.pop();
}
prev = stk.top();
prev->next = curr->next;
delete curr;
return dummy->next;
}
};
方法三:快慢指针
只需要遍历一遍,非常巧妙
时间复杂度:O(n)
空间复杂度:O(1)
class Solution
{
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
ListNode* dummy = new ListNode(-1, head);
ListNode* fast = dummy;
ListNode* slow = dummy;
ListNode* prev;
ListNode* curr;
for (int i = 0; i < n; i++)
{
fast = fast->next;
}
while (fast->next != nullptr)
{
fast = fast->next;
slow = slow->next;
}
prev = slow;
curr = slow->next;
prev->next = curr->next;
delete curr;
return dummy->next;
}
};