LeetCode刷題筆記:刪除連結串列的倒數第N個節點
阿新 • • 發佈:2018-12-30
Given a linked list, remove the n-th node from the end of list and return its head.
Example:
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
Note:
Given n will always be valid.
Follow up:
Could you do this in one pass?
解題思路
由於這道題是查閱瞭解答後才pass的,解答的解釋也非常精煉,這裡就直接把解答貼過來了。
方法一:兩次遍歷法
思路
我們注意到這個問題可以容易地簡化成另一個問題:刪除從列表開頭數起的第 (L - n + 1)(L−n+1) 個結點,其中 LL 是列表的長度。只要我們找到列表的長度 L,這個問題就很容易解決。
演算法
首先我們將新增一個啞結點作為輔助,該結點位於列表頭部。啞結點用來簡化某些極端情況,例如列表中只含有一個結點,或需要刪除列表的頭部。在第一次遍歷中,我們找出列表的長度 L。然後設定一個指向啞結點的指標,並移動它遍歷列表,直至它到達第 (L - n)(L−n) 個結點那裡。我們把第 (L - n)(L−n) 個結點的 next
圖一.刪除列表中的第L-n+1個元素
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* first = (struct ListNode*)malloc(sizeof(ListNode));
ListNode* dummy = (struct ListNode*)malloc(sizeof(ListNode));
first = head;
dummy->next = head;
int size = 0;
while(first != nullptr) {
first = first->next;
size += 1;
}
first = dummy;
size -= n;
while(size > 0) {
first = first->next;
size -= 1;
}
first->next = first->next->next;
return dummy->next;
}
};
複雜度分析
- 時間複雜度:O(L)
該演算法對列表進行了兩次遍歷,首先計算了列表的長度L其次找到第(L-n)個結點。操作執行了2L-n步,時間複雜度為O(L)。 - 空間複雜度:O(L)
我們只用了常量級的額外空間。
方法二:一次遍歷演算法
演算法
上述演算法可以優化為只使用一次遍歷。我們可以使用兩個指標而不是一個指標。第一個指標從列表的開頭向前移動 n+1 步,而第二個指標將從列表的開頭出發。現在,這兩個指標被 n 個結點分開。我們通過同時移動兩個指標向前來保持這個恆定的間隔,直到第一個指標到達最後一個結點。此時第二個指標將指向從最後一個結點數起的第 n 個結點。我們重新連結第二個指標所引用的結點的 next
指標指向該結點的下下個結點。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* first = (struct ListNode*)malloc(sizeof(ListNode));
ListNode* second = (struct ListNode*)malloc(sizeof(ListNode));
ListNode* dummy = (struct ListNode*)malloc(sizeof(ListNode));
dummy->next = head;
first = dummy;
second = dummy;
for(int i = 1; i <= n + 1; ++i) {
first = first->next;
}
while(first != nullptr) {
first = first->next;
second = second->next;
}
second->next = second->next->next;
return dummy->next;
}
};
複雜度分析
- 時間複雜度:O(L)
該演算法對含有L個子節點的列表進行了一次遍歷。因此時間複雜度為O(L)。 - 空間複雜度
我們只用了常量級的額外空間。