剑指offer18:删除链表的节点(删除指定节点,删除重复节点)

题目一

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

解决思想

 法一(不采用):从链表的头结点开始,顺序遍历查找要删除的结点,并在链表中删除该结点,时间复杂度O(n)
 法二:(1)把待删结点的下一个结点的内容复制到待删结点上,覆盖原有的内容,然后把下一个结点删除,这就相当于把当前需要删除的结点删除了。

(2)若删尾结点,由于没有下一个结点,就从链表的头结点开始,顺序遍历得到该结点的前序结点,完成删除操作。

(3)链表中只有一个结点,即删除头结点或尾结点,既然会改变头结点,所以这个函数传参时应该传头结点指针的地址(二级指针),在删除之后还需要把链表的头结点设置为NULL。

代码实现

struct ListNode  //构造结点
{
	int m_nValue;
	ListNode* m_pNext;
};

typedef struct  LinkList  //构造链表
{
	LinkList *head;  //链表头结点
	int count;       //链表中结点个数
};
 
void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted)
{
	if (pListHead == NULL || pToBeDeleted == NULL)//不存在头结点或待删结点返回
	{
		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)我们可以用一个指针记录当前值,另一个指针向后遍历,如果下一个节点值跟当前节点值的数值相等,则为重复就进行删除。

(2)我们每次都判断当前结点的值与下一个节点的值是否重复如果重复就循环寻找下一个不重复的节点,将他们链接到新链表的尾部,即就是删除重复的节点。

       建立三个指针pre、p、next,分别指向当前节点的前序节点、当前节点、当前节点的后续节点;最后循环遍历整个链表,如果节点p的值和节点next的值相同,则删除节点p和节点next,pre和下一个没有重复的节点连接。如果节点p的值和节点next的值不同,则三个指针向后移动一个指针。

代码实现

struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
		val(x), next(NULL) {
	}
};

class Solution {
public:
	ListNode* deleteDuplication(ListNode* pHead)
	{
		if (pHead == NULL || pHead->next == NULL)
		{
			return pHead;
		}
		else
		{
			// 新建一个头节点,防止第一个结点被删除
			ListNode* newHead = new ListNode(-1);
			newHead->next = pHead;

			// 建立索引指针
			ListNode* p = pHead;      // 当前节点
			ListNode* pre = newHead;  // 当前节点的前序节点
			ListNode* next = p->next;    // 当前节点的后序节点

			//从头到尾遍历链表
			while (p != NULL && p->next != NULL)
			{
				if (p->val == next->val)//如果当前节点的值和下一个节点的值相等
				{
					// 循环查找,找到与当前节点不同的节点
					while (next != NULL && next->val == p->val)
					{
						ListNode* temp = next;
						next = next->next;
						// 删除内存中的重复节点
						delete temp;
						temp = nullptr;
					}
					pre->next = next;
					p = next;
				}
				else  //如果当前节点和下一个节点值不等,则向后移动一位
				{
					pre = p;
					p = p->next;
				}
				next = p->next;
			}
			return newHead->next;  //返回头结点的下一个节点
		}
	}
};

相关学习也可参考:https://blog.youkuaiyun.com/Tianzez/article/details/79965449

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值