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;
}
};