LeetCode-19

2019/04/03

方法一:遍历两次链表,第一次遍历得到链表的长度,第二次遍历找到倒数第n个节点并删除它。

时间复杂度为O(6n),空间复杂度为O(1)

方法二:遍历一遍链表,遍历链表的同时将各节点地址放入容器中,遍历结束后通过容器下表删除倒数第n个节点。

时间复杂度为O(4n),空间复杂度为O(n)

ListNode* removeNthFromEnd(ListNode* head, int n) {
    vector<ListNode*> nodeVector;    //创建一个节点容器
    ListNode* pWorkNode = head;
    int i = 0;    //链表长度
        
    while (pWorkNode)    //遍历链表
    {
        nodeVector.push_back(pWorkNode);    //将各个节点放入容器中
        pWorkNode = pWorkNode->next;
        ++i;
    }
        
    int j = i + 1 - n;    //待删除节点序号
    if (1 == j)    //如果删除的是第一个节点
    {
        pWorkNode = head->next;
        delete head;
        head = pWorkNode;
    }
    else
    {
        nodeVector[j - 2]->next = nodeVector[j - 1]->next;
        delete nodeVector[j - 1];
    }
        
    return head;
}

    这个算法实现非常差,时间复杂度并没有比遍历两边链表低多少,空间复杂度却变大很多。想的时候只记得降低遍历次数,没有更深的去想怎么降低遍历次数的同时使得空间复杂度仍是O(1)。

方法三:这个算法是看了别人才反应过来的,关键就在于怎么在依次遍历中确定这个节点顺序排在第几位。

时间复杂度为O(2n), 空间复杂度为O(1)

ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode* pFirstNode = new ListNode(0);    //为了统一删除节点的操作
    pFirstNode->next = head;
    ListNode* pWorkNode1 = head;    //确定待删除节点的顺序位置
    ListNode* pWorkNode2 = pFirstNode;     //遍历到待删除节点

    while(n--)
        pWorkNode1 = pWorkNode1->next;
    while(pWorkNode1)    //遍历到待删除节点的前一个节点
    {
        pWorkNode1 = pWorkNode1->next;
        pWorkNode2 = pWorkNode2->next;
    }
    pWorkNode1 = pWorkNode2->next;
    pWorkNode2->next = pWorkNode1->next;
    delete pWorkNode1;

    return pFirstNode->next;  
}

总结:做题的时候就要多想,并不是说怎么把它实现了,而是怎么把它实现的更好,实现了有没有更好的方法,要多想!

猜你喜欢

转载自www.cnblogs.com/zpchya/p/10651881.html