删除链表的倒数第N个节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

方法一:

希望是O(N)的算法,通过一次遍历来解决问题.

首先题目中说了,要删除的是倒数第N个节点,那我就可以想成,他希望删除的是正数第count-N+1个节点,

接着通过在对链表进行遍历的时候计数就可以解决该问题,我们已经知道希望删除的是正数的第count-N+1个节点

那我们在遍历到正数的第count-N个节点时,停下来,就可以将第count-N+1个节点删除,并修复链表的节点关系

只是需要对删除正数的第一个节点做一下特殊的处理即可。

代码实现:
 struct ListNode {
    int val;
   struct ListNode *next;
 };
 
 struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    int count=0;
    struct ListNode * head_ptr=head;
    while(head_ptr !=NULL){

//先通过一次遍历得到链表中有多少个节点
        head_ptr=head_ptr->next;
        count++;
    }
    
    int num_from_top=count-n+1;  // delete node num;

//得到从正这数,应该删除的是第几个节点
    head_ptr=head;  
    if(num_from_top == 1){

//将删除头结点的情况单独拿出来处理
        struct ListNode * ptr=head_ptr;
        head_ptr=head_ptr->next;
        free(ptr);
        goto end;
    }

    int num=1;
    struct ListNode *cur_ptr=head; //让当前指针指向头结点

    while(cur_ptr!=NULL){

// 开始循环遍历链表
        if(num == num_from_top-1){ // node before the one  which will be deleted;

//找到需要删除的节点的前一个节点的时候,停止遍历,此时next指针就是需要删除的节点
               struct ListNode * del_node =cur_ptr->next;

     cur_ptr->next=del_node->next;
                free(del_node);
               goto end;
        }else{
            cur_ptr=next_ptr;
            num++;
        }
    }

end:
    return   head_ptr;
}

 

方法二:

使用双指针的方法,整体思路是让前面的指针先移动n步,之后前后指针共同移动直到前面的指针到尾部为止。

首先创建了一个哨兵节点sentinel, sentinel->next指向传入的head节点,然后声明两个指针变量  start 与end

使他们都指向哨兵节点

 

先让start移动N下,然后接着在开始让start与end节点同时移动,当start到了结尾的NULL的时候,此时end节点刚好在需要删除的位置处

但是该题要求删除倒数第N个位置的节点,所以我们控制循环的条件,让start移动到最后一个节点即可,在例子中也就是5的位置,此时end节点应该在

3的位置,恰好就是需要删除的那个节点之前的位置,操作指针,删除节点,修复链表即可

最后将sentinel-next指向的节点返回即可。

以下的代码中,给大家了一个main函数,便于测试与调试用。

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
        struct ListNode * sentinel = malloc(sizeof(struct ListNode));
        sentinel->next=head;
        struct ListNode *ret_head=NULL;
        struct ListNode * start , *end;
        start=end=sentinel;
        while(n!=0){
                start=start->next;
                n--;
        }

        while(start->next!=NULL){
                start=start->next;
                end=end->next;
        }
        struct ListNode *del_node=end->next;
        end->next=end->next->next;
        free(del_node);
        ret_head=sentinel->next;
        free(sentinel);
        return ret_head;
}

int main(){
    int nums[]={1,2,3,4,5};
    int n=2;
    struct  ListNode * head=NULL;
    struct  ListNode * tail=NULL;
    int nums_num=sizeof(nums)/sizeof(int);
    int ii=0;
    for(;ii<nums_num;ii++){
        struct ListNode *  ptr=malloc(sizeof(struct ListNode));
        ptr->next=NULL;
        ptr->val=nums[ii];
        if(!head){
            tail=head=ptr;
        }else{
            tail->next=ptr;
            tail=ptr;
        }
    }

    struct ListNode * ret_list=removeNthFromEnd(head, n);
    while(ret_list !=NULL){
        printf("%d->", ret_list->val);
        struct ListNode * ptr=ret_list;
        ret_list=ret_list->next;
        free(ptr);
    }
    
}


来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

posted on 2020-03-08 22:29  PigDragon  阅读(337)  评论(0编辑  收藏  举报