Problem: 19. 删除链表的倒数第 N 个结点
方法一:两次遍历
思路
首先遍历链表获取链表长度 s i z e size size,则对第 s i z e − k size - k size−k个结点执行删除操作: c u r → n e x t = c u r → n e x t → n e x t cur \rightarrow next=cur \rightarrow next \rightarrow next cur→next=cur→next→next
为了避免特殊讨论头结点被删除的情况,增加一个哑结点 d u m m y dummy dummy, d u m m y → n e x t = h e a d dummy \rightarrow next = head dummy→next=head。最终返回 d u m m y → n e x t dummy \rightarrow next dummy→next
Code
/**
* 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) {
int size = 0;
ListNode* dummy = new ListNode(-1, head), *cur = head;
while(cur){
cur = cur->next;
size++;
}
cur = dummy;
for(int i = 0; i < size - n; i++){
cur = cur->next;
}
cur->next = cur->next->next;
return dummy->next;
}
};
复杂度
-
时间复杂度:
O ( n ) O(n) O(n), n n n为链表长度。 -
空间复杂度:
O ( 1 ) O(1) O(1)
方法二:双指针
思路
方法一中由于需要获取链表长度 s i z e size size额外遍历了一次链表,我们可以通过使用双指针遍历一次链表来继续优化。设双指针 s l o w slow slow、 f a s t fast fast, f a s t fast fast的结束位置在链表尾部所指向的 ∅ \emptyset ∅, s l o w slow slow的位置在第倒数 n + 1 n+1 n+1的位置。此时对 s l o w slow slow执行删除操作,即 s l o w → n e x t = s l o w → n e x t → n e x t slow \rightarrow next = slow \rightarrow next \rightarrow next slow→next=slow→next→next 。
我们设置慢指针初始位置在 d u m m y dummy dummy, d u m m y → n e x t = h e a d dummy \rightarrow next = head dummy→next=head。快指针初始位置在 h e a d head head,让它先跑 n n n个结点,当快指针跳出循环时,执行删除操作,返回 d u m m y → n e x t dummy \rightarrow next dummy→next。
Code
/**
* 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) {
ListNode* dummy = new ListNode(-1, head);
ListNode* slow = dummy, *fast = head;
for(int i = 0; i < n; i++){
fast = fast->next;
}
while(fast){
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
return dummy->next;
}
};
复杂度
-
时间复杂度:
O ( n ) O(n) O(n), n n n为链表长度。 -
空间复杂度:
O ( 1 ) O(1) O(1)