1. 最簡單的想法就是先求出鏈表的長度len,再找到(len-k)個節點,即刪除節點的前一個節點,就可以將其刪除.
2. 兩次遍歷.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head==NULL) return head;
ListNode* tmp = head;
int count = 0;
//求鏈表長度.注意
//不要用head求,會改變head,另外指定tmp.
while(tmp!=NULL) {
tmp = tmp->next;
count++;
}
//啞結點消除刪除只剩一個節點情況,以及刪除第一個節點的情況
//的邊界條件.
ListNode* dummy = new ListNode(0);
dummy->next = head;
tmp = dummy;
int c = 0;
while(c!=count-n) {
tmp = tmp->next;
c++;
}
//找到了就停止.
tmp->next = tmp->next->next;
//返回啞結點的後一個節點.
return dummy->next;
}
};
3. 一次遍歷
4. 可以優化爲只使用一次遍歷.使用雙指針.快慢指針,快指針先走n-2,然後快慢指針一起走,這樣快慢指針的間隔保持恆定的間隔,即可以求得其倒數第n個節點前一個節點,便可以將倒數第n個節點刪除了.
5. 快慢指針找到倒數第N個節點.
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head==NULL) return head;
ListNode* dummy = new ListNode(0);
//啞結點消除邊界情況,比如只剩一個數,
//或者刪除第一個節點.
dummy->next = head;
ListNode* slow = dummy;
ListNode* fast = dummy;
//使快慢指針的間隔爲n.
for(int i=1;i<=n;i++) {
fast = fast->next;
}
//這樣當快指針走到末尾時,慢指針
//就是倒數第N個節點.
while(fast->next!=NULL) {
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
return dummy->next;
}
};
三. 遞歸方法
1. 遞歸方法分爲遞和歸兩個過程.
2. 遞歸不好理解的時候可以具體舉幾個簡單的例子, 比如[1],1即一個數的情況.
class Solution {
public:
int i=0;
ListNode* removeNthFromEnd(ListNode* head, int n) {
//先是遞的過程,如果找到最後一個節點,直接返回NULL;
if(head==NULL) return NULL;
//當前指針下一個指針是哪個.
head->next = removeNthFromEnd(head->next,n);
//歸的時候統計當前是第幾個指針.
i++;
//如果是待刪除指針,返回當前指針下一個
//否則返回head.
if(i==n) return head->next;
else return head;
}
};