• 第18题:在O(1)时间删除链表结点+删除链表中重复的节点


    题目描述:题目描述在O(1)时间删除链表结点
    给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。

    考查创新编程能力。

    思路:

    1.如果从头到尾遍历,时间O(n)

    2.如果将待删除节点的下一个节点j复制到待删除节点i上,然后将i的下一个节点指向j的下一个节点,删除j的节点。

    3.对于尾节点,需要从头开始遍历

    4.对于只有一个节点的链表,要将*HeadNode设置为Nullptr.

    5.时间复杂度

    n-1个非尾节点,时间O(1)

    1个尾节点,时间O(n)

    最终((n-1)*O(1)+O(n))/n=O(1)符合题目要求

    注意:

    1.每次删除完节点后,要释放节点,即将节点的指针设为nullptr。

    2.n-1个非尾节点,删除的是待删除节点的下一个pNext,而不是本身的节点。

    3.最后一个尾节点,用while遍历,pNode指针向后指,找到最后一个节点,删除后,将pNode->Next设为nullptr。

    //已知该节点存在链表中
    void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted)
    {
    	//1.如果链表头节点或待删除节点为空,返回
    	if (!pListHead || !pToBeDeleted)
    		return;
    	//2.多个节点的链表,前n-1个非尾节点
    	if (pToBeDeleted->m_pNext)
    	{
    		//2.1 pNext:待删除节点J的下个节点K
    		ListNode* pNext = pToBeDeleted->m_pNext;
    		//2.2 复制值J=K
    		pToBeDeleted->m_nValue = pNext->m_nValue;
    		//2.3 复制指针J->NEXT=K->NEXT
    		pToBeDeleted->m_pNext = pNext->m_pNext;
    
    		//2.4 删去下个节点K(pNext)
    		delete pNext;
    
    		//2.5 pNext设为空指针
    		pNext = nullptr;
    
    	}
    
    	//3.只有一个节点的链表,删完要将头节点指针设为空
    	else if(*pListHead==pToBeDeleted)
    	{
    		//3.1删除节点
    		delete pToBeDeleted; 
    
    		//3.2 释放删除节点的指针
    		pToBeDeleted = nullptr;
    
    		//3.3 删除后将头节点设为空指针
    		*pListHead = nullptr;
    
    	}
    	//4.如果是最后一个尾节点,就用遍历
    	else
    	{
    		//4.1 pNode:遍历指针,从头开始
    		ListNode* pNode = *pListHead;
    		//4.2 while遍历找到pNode的下一个节点是要删除的节点
    		while(pNode->m_pNext == pToBeDeleted)
    		{ 
    			//4.2.1 指针向后指
    			pNode = pNode->m_pNext; 
    		}
    		//4.3 将pNode的下一个节点设为空
    		pNode->m_pNext = nullptr;
    
    		//4.4 删除最后的节点
    		delete pToBeDeleted;
    		//4.5 释放指针 
    		pToBeDeleted = nullptr; 
    
    	}
    
    
    }
    

    题目描述

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

    思路:

    1.确定函数的参数,头节点也可能被删除,所以函数声明应该为

    void deleteDuplication(ListNode** pHead);

    2.从头到尾遍历链表,确保pPreNode始终和下一个没有重复的节点连在一起。

    //函数的参数:ListNode** pHead。
    //因为头节点可能重复,会被删除,所以不用ListNode* pHead
    void DeleteDuplication(ListNode** pHead) 
    {
    	//1.如果是空链表或头节点为空,返回 
    	if (!pHead || !*pHead) 
    		return;
    	 
    	//2.ListNode* pNode:初始化指向当前头节点*pHead
    	ListNode* pNode = *pHead;
    	 
    	//3.ListNode* pPreNode:指向上个节点,初始化为空
    	ListNode* pPreNode = nullptr;
    
    	//4.循环遍历
    	while (pNode)
    	{
    		//4.1.新建一个节点pNext,指向下个节点
    		ListNode* pNext = pNode->m_pNext;
    
    		//4.2 设置标记:pNode节点是否需要删除
    		bool needDetele = false;
    
    		//4.3 如果下个节点pNext不为空,且pNode节点值和下个节点pNext的值相同,pNode节点就需要删除
    		if (pNext!=nullptr && pNext->m_nValue == pNode->m_nValue)
    			needDetele = true;
    		   
    
    		//4.4 如果不需要删除,就遍历下一个
    		if (!needDetele)
    		{
    			//4.4.1 上个节点pPreNode设为当前节点pNode 
    			pPreNode = pNode;
    
    			//4.4.2 当前节点pNode设为下个节点pNext
    			pNode = pNext;
    
    		/*	pNode->m_nValue = pNext->m_nValue;
    			pNode->m_pNext = pNext->m_pNext;*/
    		}
     
    		//4.5 否则,开始删除
    		else
    		{
    			//4.5.1 记录pNode值
    			int value = pNode->m_nValue;
    
    			//4.5.2 定义要删除的节点变量toBeDeleted,初始化为该节点
    			ListNode* toBeDeleted = pNode; 
    	 
    			//4.5.3 循环遍历:如果toBeDeleted节点不为空,且等于下一个节点,就将toBeDeleted删除,
    			while (toBeDeleted&&value == toBeDeleted->m_nValue)
    			{
    				//4.5.3.1 pNext指向toBeDeleted下个节点
    				pNext = toBeDeleted->m_pNext;
    
    				//4.5.3.2 删除toBeDeleted节点
    				delete toBeDeleted;
    				toBeDeleted = nullptr;
    
    				//4.5.3.3 toBeDeleted节点赋值为下个节点pNext
    				toBeDeleted = pNext; 
    			} 
    
    			//4.5.4 如果删除的是头节点,即pPreNode为空,将头节点改为下个节点
    			if (!pPreNode)
    				*pHead = pNext;
    			//4.5.5 否则,将pPreNode的下个节点设置为下个节点pNext
    			else
    				pPreNode->m_pNext = pNext;
    
    			//4.5.6 当前节点pNode设为下个节点pNext
    			pNode = pNext;
    		}	
    	}
    }

    第二遍

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    class Solution {
    public:
        ListNode* deleteDuplication(ListNode* pHead)
        {
            //1.如果链表为空或者头节点为空,返回nullptr
            if(!pHead)
                return nullptr;
            
            //2.pPreNode指向上一个节点,初始化为nullptr;
            ListNode* pPreNode = nullptr;
            
            //3.当前节点pNode,初始化指向头节点
            ListNode* pNode=pHead;
            
            //4.删除重复节点,while循环条件:pNode不为空
            while(pNode)
            {
                //4.1 pNext指向pNode下个节点
                ListNode* pNext= pNode->next;
                
                //4.2 bool标记pNode是否需要删除,默认值false
                bool needDelete=false;
                
                //4.3 更新needDelete标记值:如果pNode的值和下个节点pNext的值相等的话,这个节点需要删除
                if(pNext&&pNode->val==pNext->val)
                    needDelete=true;
                
                //4.4 如果不需要删除,当前节点pNode向后指一个pNext,上一个节点pPreNode指向当前节点
                if(!needDelete)
                {
                    pPreNode=pNode;
                    pNode=pNext;
                }
                //4.5 否则需要删除
                else
                {
                    //4.5.1 存放当前pNode的值int
                    int value=pNode->val;
                    
                    //4.5.2 定义待删除的节点toBeDeleted
                    ListNode* toBeDeleted=pNode;
                    
                    //4.5.2 如果待删除的节点toBeDeleted存在,且值等于当前pNode的值,则删除该节点
                    while(toBeDeleted&&toBeDeleted->val==value)
                    {
                        //4.5.2.1 保存待删除节点的下个节点
                        pNext=toBeDeleted->next;
                        
                        //4.5.2.2 删除该节点
                        delete toBeDeleted;
                        toBeDeleted=nullptr;
                        
                        //4.5.2.3 重新更新待删除的节点
                        toBeDeleted=pNext;
                        
                    }
                    //4.5.3 如果上个节点为空,即头节点被删除,头节点为pNext
                    if(!pPreNode)
                        pHead=pNext;
                    //4.5.4上一个节点pPreNode指向当前节点
                    else
                       pPreNode->next=pNext;
                    
                    //4.6 将当前节点pNode向后指一个pNext 
                    pNode=pNext;
                }
            }
        //5. 返回链表
        return pHead;
        }
    };

    网友的

    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;
            }    
        }
    };
  • 相关阅读:
    线性表ADT实现
    基数排序
    二叉树之已知前序和中序遍历求后序遍历(POJ2255 &&HDU )
    acm头文件
    快排
    快读
    二分
    数据结构大师
    AC_2. 01背包问题
    AC_94. 递归实现排列型枚举
  • 原文地址:https://www.cnblogs.com/lightmare/p/10425087.html
Copyright © 2020-2023  润新知