(剑指Offer)面试题13:在O(1)时间内删除链表结点

题目:

在给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间内删除该结点。链表结点与函数的定义如下:

struct ListNode{
int val;
ListNode* next;
};

void deleteNode(ListNode** pListHead,ListNode* pToBeDeleted)

思路:

删除链表结点的一般思路是:从头指针开始遍历,找到要删除结点的前一结点pPrev,然后pPrev->next=pToBeDeleted->next,(还需考虑删除结点是否为头结点),这样的时间复杂度为O(n)。

而题目要求为O(1),找到删除结点的前一结点复杂度为O(n),但找到后一结点的复杂度为O(1),如果我们把后一结点的东西拷贝到要删除结点上,再把后一结点删除,岂不就是相当于把当前需要删除的结点删除了?

ListNode* pNext=pToBeDeleted->next;
pToBeDeleted->val=pNext->val;
pToBeDeleted->next=pNext->next;
delete pNext;
pNext=NULL;

考虑特殊情况,如果要删除的结点为头结点和尾结点怎么办?

头结点:要删除的结点为头结点,删除之后,链表为空,此时需要将头结点置为NULL,这时候改变的头指针的内存地址,因此需要传递二级指针,*pHead=NULL;

尾结点:要删除的结点为尾结点,尾结点没有后一结点,因此,不能通过上述方法来解决,还要回到传统的遍历方法,找到它的前一结点,然后将它的下一结点置为NULL,同时删除尾指针。

代码:

struct ListNode{
int val;
ListNode* next;
};

void deleteNode(ListNode** pListHead,ListNode* pToBeDeleted){
    if(pListHead==NULL || pToBeDeleted==NULL)
        return;
    if(pToBeDeleted->next!=NULL){
        ListNode* pNext=pToBeDeleted->next;
        pToBeDeleted->val=pNext->val;
        pToBeDeleted->next=pNext->next;
        delete pNext;
        pNext=NULL;
    }
    else if(*pListHead==pToBeDeleted){
        delete pToBeDeleted;
        pToBeDeleted=NULL;
        *pListHead=NULL;
    }
    else{
        ListNode* pNode=*pListHead;
        while(pNode->next!=pToBeDeleted)
            pNode=pNode->next;
        pNode->next=NULL;
        delete pToBeDeleted;
        pToBeDeleted=NULL;
    }
}

你可能感兴趣的:(面试题)