删除链表中重复的节点(经典链表面试题)

#题目

删除链表中重复的节点
在一个排序,如何删除重复的节点?
例如:1 -> 2 -> 3 -> 3 -> 4
删除后是 1 -> 2 -> 4

##分析
在链表的面试题中,重要一点是要注意对链表的情况要全部考虑到,或许你在看到上面的例子后按照给出的例子大笔一挥,写出代码后,那么你很可能就已经凉凉。。。

首先我们应该考虑大部分情况,也就是上面例子的情况,但是我们不能急于下笔,应该再考虑,如果在传参的时候,调用者传NULL?在处理链表的过程中,如果链表有一个节点会怎么样,两个呢?要是没有重复的节点呢?如果全是重复的节点呢?还要注意,在没带头节点的情况中,头节点怎么处理?
想完这么多可能会觉得这么多情况怎么处理,不要急,我们一项一项的写,写的时候要注意自己意识到的情况,我们可以用写注释的方式,先写出情况。

对这道题我们来写一下代码~ 分析分析
写链表中我们知道对于单链表访问最大的缺点就是只能单向,从前向后,所以我们删除也是一样,删除当前就得知道当前的上一个节点,那么我们这里采用指针记录的方式。

###方法1(粗暴)
我们采用最容易想到的方法,不用考虑时间效率与空间效率问题,就直接用遍历,用一个哈希表结构来记录每个节点对应的值在节点中出现了几次,统计完成后,然后通过哈希表中如果出现次数为大于等于2,再用两个指针一个前一个后开始找对应的值就行了,如果后一个指针指向的节点的值为哈希表中出现次数大于等于2的数,那么前一个指针指向后一个指针的next然后删除后一个指针所指向的节点,让后一个指针重新指向前一个指针的next,就这样就可以完成删除。

虽然这个方法可以,但是时间复杂度为O(N), 空间复杂度为一个哈希表的结构,所以采用这种不是最佳选择。

###方法2(三指针法)
采用三个指针来进行遍历,同时删除重复的节点,因为是有序的链表,我们就可以确定,重复的元素肯定是在一块链接,所以我们就可以,用三指针,我们这里就叫
pre、cur、nex 分别代表的是前中后三个指针,我们在考虑的情况中,如果头节点开始就重复,我们就处理很起来多了一种情况就需要额外处理,所以我们添加一个头节点,变成带头节点,保证了头节点开始不会重复,那么我们就可以开是让pre指向带头的节点,cur指向pre的next,nex指向cur的next。

接下来我们就可以看cur是否和nex相等,相等就让nex继续向下走,不相等然后再处理删除,cur开始到nex中间节点都是要删除的(包含cur指向,不包含nex指向)删除,就用到了pre,删除完成让pre指向cur就可以了。

如果cur值与nex值不相等,那么就可以三个指针各自往前移动一个。

下来我来看代码~

ListNode* deleteDuplication(ListNode* pHead)
{
	// 先判断空
	if (pHead == NULL)
	{
		return NULL;
	}
	// 判断是否只有一个节点
	if (pHead->next == NULL)
	{
		return pHead;
	}
	// 我们采用带头链表,自己添加一个头
	ListNode* pre = new ListNode();
	pre->next = pHead; // 把头节点链接在链表上
	ListNode* pre_head = pre; // 用来保存头节点,用于返回删除后的链表
	ListNode* cur = pHead; //中指针
	ListNode* nex = pHead->next; // 后面指针
	while (nex != NULL) // 结束条件
		while (nex != NULL && cur->val == nex->val) 
		{
			nex = nex->next;
		}
		// 如果没有重复的那么cur的next一定等于nex
		if (cur->next != nex) // 如果相等说明没有相同的节点
		{
			while (cur != nex) // 删除动作
			{
				pre->next = cur->next;
				delete cur;
				cur = pre->next;
			}
			if (nex != NULL) // 这里一定要要注意,要防止走到NULL发生段错误
			nex = nex->next;
		}
		else
		{
			// 处理没有重复的情况
			pre = cur;
			nex = nex->next;
			cur = cur->next;
		}
	}
	ListNode* head = pre_head->next; // 释放空间,防止内存泄漏
	delete pre_head;
	return head;
}

我们测试要尽可能的全面
1)传NULL
2)只有一个节点
3)头节点开始就有重复
4)中间节点重复
5)尾部节点重复
6)链表中没有重复链表
7)所有节点都是重复的

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页