題目的意思很簡單,就是刪除一個鏈表倒數第N個節點。
需要用到鏈表的標準操作:快慢指針。
我們讓一個快指針先指向第N個元素,這個時候快指針總比慢指針領先N個元素,等到快指針指向鏈表尾部的時候慢指針就指向需要刪除的元素。
之前已經用了幾次了(比如空間復雜度O(1)O(1)O(1)判斷鏈表是否有環以及環的位置),但是我看到這道題竟然還是一下沒有想到。
順帶懺悔一下,之前說好每天至少一道題解的,但是前面忙其他的事就沒有弄了,罪過罪過,后面要繼續堅持。
看題解學到鏈表的一個操作:啞指針。因為我們一般得到的都是鏈表的頭部,這樣對鏈表進行刪除的時候就需要特別判斷一下是不是首部,如果是首部的話是沒有前驅節點的。但是如果加上啞節點就不會有這種問題了。(實用小技巧加一)
如果要刪除節點的話就從啞節點開始訪問,然后就會訪問到需要刪除節點的前一個。
/*** 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(0, head);ListNode *first = head;for(int i=0; i<n; ++i) first = first->next;ListNode *second = dummy;while(first){first = first->next;second = second->next;}second->next = second->next->next;head = dummy->next;delete dummy;return head;}
};
之前在看對Linus的采訪的時候學到一種新的操作鏈表的方法,那就是二級指針。
我們對于內存塊的控制都是通過指針進行的,因此我們控制鏈表的核心就是控制指針的值。但是只使用一級指針是無法直接改變指針的值的,因為我們會對指向某個內存塊的指針進行一次復制,而無法對我們需要返回的那個指針進行修改。為了修改那個指針,我們一般需要保存前驅節點來得到指向對應內存塊的指針。
但是使用二級指針以后就可以避免這個問題,因為使用二級指針的話我們是直接對原數據中指向內存塊的指針進行操作的。這樣就不需要前驅節點。
/*** 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 *first = head;for(int i=0; i<n; ++i) first = first->next;ListNode **second = &head;while(first){first = first->next;second = &(*second)->next;}*second = (*second)->next;return head;}
};