面试题18:删除链表的节点

题目一:在O(1)时间内删除链表节点

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

struct ListNode
{
    int m_nValue;
    ListNode* m_pnext;
};

void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted);

常规做法是从链表的头结点开始,顺序遍历查找要删除的节点,并在链表中删除该节点,但此时的时间复杂度为O(n),这种做法默认的前提是先要找到要删除节点的前一个节点

推荐做法是对n-1个非尾节点而言,可以在O(1)时间内把下一个节点的内存复制覆盖要删除的节点,并删除下一个节点;对于尾节点而言,仍然需要顺序查找,时间复杂度为O(n)。总的时间复杂度为

[(n-1)*O()+O()]/n=O(1),符合要求。

void DeleteNode(ListNode**pListHead, ListNode* pToBeDeleted)
{
    if(!pListHead || !pToBeDeleted)
        return;
    //要删除的节点不是尾节点
    if(pToBeDeleted->m_pNext != NULL)
    {
        ListNode* pNext = pToBeDeleted -> m_pNext;
        pToBeDeleted -> m_nValue = pNext -> m_nValue;
        pToBeDeleted -> m_pNext = pNext -> m_pNext;

        delete pNext;
        pNext = NULL;
    } else if(*pListHead == pToBeDeleted)//链表只有一个节点,删除头结点(也是尾节点)
    {
        delete pToBeDeleted;
        pToBeDeleted = NULL;
        *pListHead = NULL;
    } else {//链表中有多个节点,删除尾节点
        ListNode* pNode = *pListHead;
        while(pNode -> m_pNext != pToBeDeleted)
        {
            pNode = pNode -> m_pNext;
        }

        pNode -> m_pNext = NULL;
        delete pToBeDeleted;
        pToBeDeleted = NULL;
    }
}

所以,要删除一个节点时,并不一定要删除这个节点本身,可以先把下一个节点的内容复制出来覆盖被删除节点的内容,然后把下一个节点删除。

题目二:删除排序链表中重复节点,重复节点不保留

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

牛客网上的大佬解答:

1.递归

class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {
        if (pHead==NULL)
            return NULL;
        if (pHead!=NULL && pHead->next==NULL)
            return pHead;
                 
        ListNode* current;
         
        if ( pHead->next->val==pHead->val){
            current=pHead->next->next;
            while (current != NULL && current->val==pHead->val)
                current=current->next;
            return deleteDuplication(current);                     
        }
         
        else {
            current=pHead->next;
            pHead->next=deleteDuplication(current);
            return pHead;
        }    
    }
};

2.思路清晰

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
{
    if( pHead == NULL ) return pHead;
 
    ListNode *pre = NULL; //指向前面最晚访问过的不重复结点
    ListNode *p = pHead; //指向当前处理的结点
    ListNode *q = NULL; //指向当前处理结点后面结点
 
    while( p != NULL )
    {
        //当前结点p,(其实是p指向当前结点),与它下一个结点p->next的val相同,说明要删掉有这个val的所有结点
        if( p->next != NULL && p->next->val == p->val )
        {
            q = p->next;
 
            //找到q,它指向最后一个与p val相同的结点,那p 到 q (包含) 都是要删除的
            while( q != NULL && q->next != NULL && q->next->val == p->val )
            {
                q = q->next;
            }
 
            //如果p指向链表中第一个元素,p -> ... -> q ->... , 要删除p到q, 将指向链表第一个元素的指针pHead指向q->next。
            if( p == pHead )
            {
                pHead = q->next;
            }
            else//如果p不指向链表中第一个元素,pre -> p ->...->q ->... ,要删除p到q,即pre->next = q->next
            {
                pre->next = q->next;
            }
            //当前处理的p要向链表尾部移动
            p = q->next;
        }
        else
        {
            pre = p;
            p = p->next;
        }
    }
    return pHead;
}
 
};

猜你喜欢

转载自blog.csdn.net/R_g_Luo/article/details/89683057