给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1 输出:[]
示例 3:
输入:head = [1,2], n = 1 输出:[1]
提示:
- 链表中结点的数目为
sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
题目分析
这题我们可以获取链表的长度,然后通过遍历数组来删除指定节点。
解题思路
第一张方法
链表的长度就是其中节点的个数,而最后一个节点指向NULL我们可以利用这一特性来求链表的长度,为了使代码更简洁我们用函数单独包装这一过程,循环的过程中头指针不断向后移动,直到头指针为NULL,然后返回指针长度。在此处为了方便计算,我们给链表添加了虚拟头节点prev,然后使指针cur指向prev的地址,然后继续循环,使cur移动到需要删除的节点前一位,使其直接指向后俩位的节点,起到了删除该节点的效果。但这种方法等于要遍历俩遍链表,显得比较繁琐。而且考虑到节点可能是通过malloc方法创建的,所以删除节点后,要释放该节点所占内存,以免内存泄漏。
int getLength(struct ListNode*head) {
int i = 0;
while(head){
head = head->next;
i++;
}
return i;
}
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
struct ListNode prev;
prev.next=head;
struct ListNode* cur = &prev;
int length = getLength(head);
for(int j =1 ;j<length-n+1;j++) {
cur=cur->next;
}
cur->next = cur->next->next;
return prev.next;
}
第二种方法
我们可以使用双指针,一个快指针,一个慢指针,开始先让快指针比慢指针移动n个节点,此时若快指针的下一个节点为NULL则说明n超出链表长度,返回原来的头节点,若没有,则快指针移动n个节点,然后快慢指针一起移动,若块指针到达链表尾部,则慢指针的下一个节点就是倒数第n个节点,然后下面操作就与上面相同
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
struct ListNode xuni;
xuni.next = head;
struct ListNode* first = &xuni;
struct ListNode* second = &xuni;
for(int i=0;i<n;i++) {
if(!first->next) {
return head;
}
first = first->next;
}
while(first->next) {
first = first->next;
second = second->next;
}
struct ListNode* cur =second->next;
second->next = second->next->next;
free(cur);
return xuni.next;
}