方法1:由于链表不能随机访问,所以很自然的想法是第一遍得到链表长度,然后计算倒数第n个结点的位置,但这样时间复杂度O(n2),想到用空间换取时间,可以用一个地址数组存储每个结点的地址,然后直接删除掉倒数第n个,返回头结点。
方法2:上面的方法虽然时间复杂度达到了线性,但是需要额外的空间,更好的方法是采用双指针追赶,设慢指针为pre,快指针为post,先让post指针走n步,然后pre指针开始走,这样当post走到最后的时候,pre指针就指向需要删除结点的位置,因为删除需要前继结点的位置,所以每走一步就需要保存前继结点,最后需要特殊处理的就是删除头结点的话直接返回第二个结点就好了。
遍历法:
1 class Solution { 2 3 public: 4 5 ListNode*removeNthFromEnd(ListNode* head, int n) { 6 7 ListNode*t[100]; 8 9 int i = 0; 10 11 while (head) 12 13 { 14 15 t[i] =head; 16 17 ++i; 18 19 head =head->next; 20 21 } 22 23 24 25 int p = i -n; 26 27 if (i == 1) 28 29 return NULL; 30 31 else if (p ==0) 32 33 return t[p]->next; 34 35 else 36 37 { 38 39 40 41 t[p -1]->next = t[p]->next; 42 43 return t[0]; 44 45 } 46 47 } 48 49 };
双指针法:
1 /** 2 3 * Definition for singly-linked list. 4 5 * struct ListNode { 6 7 * int val; 8 9 * ListNode *next; 10 11 * ListNode(int x) : val(x), next(NULL) {} 12 13 * }; 14 15 */ 16 17 classSolution { 18 19 public: 20 21 ListNode* removeNthFromEnd(ListNode*head, int n) { 22 23 ListNode*pre = head, *p = head, *t= head; 24 25 for (int i = 0; i < n; i++) 26 27 t = t->next; 28 29 if (!t) 30 31 return head->next; 32 33 else 34 35 { 36 37 while (t) 38 39 { 40 41 t = t->next; 42 43 pre = p; 44 45 p = p->next; 46 47 } 48 49 pre->next = p->next; 50 51 return head; 52 53 } 54 55 56 57 58 59 } 60 61 };