LeetCode T19_removeNthFromEnd

方法一:两次遍历算法
思路

我们注意到这个问题可以容易地简化成另一个问题:删除从列表开头数起的第 (L - n + 1)个结点,其中 L是列表的长度。只要我们找到列表的长度 L,这个问题就很容易解决。

算法

首先我们将添加一个哑结点作为辅助,该结点位于列表头部。哑结点用来简化某些极端情况,例如列表中只含有一个结点,或需要删除列表的头部。在第一次遍历中,我们找出列表的长度 L。然后设置一个指向哑结点的指针,并移动它遍历列表,直至它到达第 (L - n)个结点那里。我们把第 (L - n)个结点的 next 指针重新链接至第 (L - n + 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) {//两次遍历
        ListNode *p = head; //定义指针P指向头节点,用于第一次遍历链表
        ListNode *pre = head; //定义指针pre指向头结点,用于第二次遍历链表
        int len = 0; //链表长度初始化
        //第一次遍历链表求链表长度
        while(p->next != NULL){
            len ++;
            p = p->next;//p指针后移一位
        }
        //第二次遍历链表,找到第(len-n)个节点,要删除的是第(len-n+1)个节点
        for(int i=0;i<(len-n);i++){
            pre = pre->next;
        }//跳出for循环后pre指向的是要删除节点的前面一个节点,第(len-n)个节点
        pre->next = pre->next->next; //让第(len-n)个节点指向第(Len-n+2)个节点,即删除了第(len-n+1)个节点
        return head;           
    }
};

 指向节点的指针变量类型也是节点!

两次遍历链表的方法较复杂,题目要求是遍历依次链表完成。

方法二:一次遍历算法:双指针

step 1:创建一个虚拟头结点,指向链表头节点。目的是在头结点有可能被删除的情况省去判断步骤;

step 2:创建两个指针first 和second,开始时都指向头节点。先让first指针后移n次,再让first指针和second每次同时后移一个节点,直到first指针指向最后一个节点,此时second指针正好指向要删除节点的前面一个节点。

step 3:创建新的节点链接关系,删除倒数第n个节点

视频学习: https://www.bilibili.com/video/av60198891?from=search&seid=2174977360875970213

C++实现: 

/**
 * 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) {//一次遍历
        //创建虚拟头节点,指向链表头节点
        auto dummy = new ListNode(-1);
        //ListNode * dummy = new ListNode(-1); //auto方法自动判定类型
        dummy->next = head;
        //定义两个指针,指向虚拟头结点
        auto first = dummy;
        auto second = dummy;
        //ListNode *first = dummy;
        //ListNode *second = dummy;
        //先让first指针后移n次
        while(n--){
            first = first->next;
        }    
        //再让first和second同时后移,直到first指向链表最后一个节点
        while(first->next != NULL){
            first = first->next; second = second->next;
        }
        //此时second正好指向倒数第n+1个节点,删除倒数第n个节点
        second->next = second->next->next;
        return dummy->next;//这里不能返回head,因为头节点有可能被删除
    }
};

加入虚拟头结点的做法不用再判断这个链表可能为空的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值