剑指offer面试题18——删除链表的节点

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

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

思路:

常规的思路是从头到尾去遍历链表,找到要删除的节点。但是这里对时间复杂度的要求是O(1)。换个角度,其实删除一个节点可以将它后继节点的数据覆盖该节点,然后删掉后继的节点就可以了。但是要考虑,被删除的节点是是否是尾节点,如果是尾节点还要考虑,这时链表中如果只有一个节点的情况。这是十分要注意的。

代码 :

struct ListNode
{
	int m_nvalue;
	ListNode* m_pNext;
};


void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted)
{
	if (!pListHead || !pToBeDeleted)
		return;
	//要删除的节点不是尾节点
	if (pToBeDeleted->m_pNext != nullptr)
	{
		ListNode* pNext = pToBeDeleted->m_pNext;
		pToBeDeleted->m_nvalue = pNext->m_nvalue;
		pToBeDeleted->m_pNext = pNext->m_pNext;
		delete pNext;
		pNext = nullptr;
	}
	//要删除的节点是尾节点,且只有这一个节点
	else if ( *pListHead == pToBeDeleted)
	{
		*pListHead == nullptr;
		delete pToBeDeleted;
		pToBeDeleted = nullptr;
	}
	//链表中有多个节点删除尾节点
	else {
		ListNode* pNext = *pListHead;
		while (pNext->m_pNext!=pToBeDeleted)
		{
			pNext = pNext->m_pNext;
		}
		pNext->m_pNext = nullptr;
		delete pToBeDeleted;
		pToBeDeleted = nullptr;
	}
		
}

题目二:删除链表中的重复节点

在一个排序链表中,如何删除重复的节点。

如上图所示, 如果节点3和4是重复节点,就将节点2和5相连。

思路:

这道题的思路还是比较朴实,就是从头节点开始遍历链表,并且记录当前节点和当前节点的前驱节点。当前节点和后继节点的值相同时,表示这两个节点为重复节点,需要删除,并且将当前节点更新为被删除节点的后继节点,如果依然为重复节点则继续删除,直到不为重复节点为止。这个时候还要判断如果前驱节点为空,即头节点为重复节点并且被删除后,需要把头节点更新为当前节点。如果前驱节点不为空,那么就把前驱节点的下一个节点指向当前节点。一定要考虑周全边界情况,比如头节点和尾节点,还有考虑前驱和后继节点的时候也要考虑是否为nullptr的情况。

代码:

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

void DeleteDuplication(ListNode**pHead)
{
	if (pHead == nullptr || *pHead == nullptr)
		return;
	ListNode*pPreNode = nullptr;
	ListNode* pNode = *pHead;
	while (pNode!=nullptr)
	{
		ListNode*pNext = pNode->m_pNext;
		bool needDelete = false;
		if (pNext != nullptr&&pNext->m_nValue == pNode->m_nValue)
			needDelete = true;
		if (!needDelete)
		{
			pPreNode = pNode;
			pNode = pNode->m_pNext;
		}
		else {
			int value = pNode->m_nValue;
			ListNode* pToBeDel = pNode;
			while (pToBeDel!=nullptr&&pToBeDel->m_nValue==value)
			{
				pNext = pToBeDel->m_pNext;
				delete pToBeDel;
				pToBeDel = nullptr;
				pToBeDel = pNext;
			}
			if (pPreNode = nullptr)
				*pHead = pNext;
			else
				pPreNode->m_pNext = pNext;
			pNode = pNext;
		}
	}
}

复习:

其实过程不复杂,但是代码写起来有点绕,过程要理清楚。

二刷代码:

struct ListNode
{
	int m_nvalue;
	ListNode* m_pNext;
};


void DeleteDuplication(ListNode** pHead)
{
	if (pHead == nullptr || *pHead == nullptr)
		return;

	ListNode* pNode = *pHead;
	ListNode* preNode = nullptr;
	
	while (pNode!=nullptr)
	{
		ListNode* pNext = pNode->m_pNext;
		bool needDelete = false;
		if (pNode->m_nvalue == pNext->m_nvalue && pNext != nullptr)
		{
			needDelete = true;
		}

		if (!needDelete)
		{
			pNode = pNode->m_pNext;
			preNode = pNode;
		}
		else
		{
			int value = pNode->m_nvalue;
			ListNode* pDelete = pNode;
			while (pDelete->m_nvalue==value&&pDelete!=nullptr)
			{
				pNext = pDelete->m_pNext;
				delete pDelete;
				pDelete = nullptr;
				
				pDelete = pNext;
			}
			if (preNode == nullptr)
				*pHead = pNext;
			else
			{
				preNode->m_pNext = pNext;
			}
			pNode = pNext;
		}
		
	}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值