面试题-----在O(1)时间删除链表结点

题目要求

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

题目分析

首先我看到这个题目,还是会惯性思维,认为删除指定结点,不就是要遍历该链表找到该结点,那就是O(n)呀。。。(无力吐槽我的智商)仔细思考一下,该函数已经给了两个已知的参数了,头节点以及待删除结点。知道待删除结点,也就等于知道了该结点的下一个结点。分析到这里,问题似乎可以解决了,删除该结点,即就是释放该结点的空间,断开该结点与它前面以及后面结点的链,看到这里还不明白的话,可以画画图。


先考虑最简单的一种情况,如果我们要在图示的这条链表中删除值c所在的结点,那么知道函数中所给的该结点,就可以将该结点的next结点中的值拷贝给该结点,如下图所示,将c覆盖,然后再将要删除的c结点的next指向原来的d结点的下一结点,图中即为尾结点tail。然后再释放图中的d结点。这样就间接的删除了待删除的C结点,此时的时间复杂度为O(1)。 (欢呼,我们做到了。。)


上面的方案似乎是很可行的,但是是不是真的完全正确那?思考一下,1)假如该链表中就只有一个头结点,上述方案就不可行了,若恰好待删除结点是头结点,那么正好我们可以碰巧删除它,并且记得最后一定要将头结点置空;2)假如链表有头有尾,我们要删除尾结点呐,此时也就只能遍历整个链表找到该结点并删除,时间复杂度为O(n)。

考虑到这里,以为要大功告成了,然而并没有。有没有考虑过对整个函数的思考过程完全建立在一种理想的情况下,那就是我们天真的以为要删除的结点在我们的链表里,所以我们是不是应该首先判断该结点有没有在链表中。但是问题又来了(心好累),查找结点必然是要遍历该链表,时间复杂度必定为O(n),看来这条路我们无法对它做出什么优化了,所以为了完成该题目,只能假设用户输入的待删除结点确确实实在我们的链表中,这个责任就交给该函数的调用者吧。

综上核心代码:

void DeleteNode(NODE **head,NODE *ToBeDelete)
{
	if(head == NULL || ToBeDelete == NULL)
		return;

	if(ToBeDelete->next != NULL)
	{
		NODE *tmp = ToBeDelete->next;
		ToBeDelete->data = tmp->data;
		ToBeDelete->next = tmp->next;

		delete tmp;
		tmp = NULL;
	}
	else if(ToBeDelete == *head)
	{
		delete ToBeDelete;
		ToBeDelete = NULL;
		*head = NULL;
	}
	else
	{
		NODE *tmp = *head;
		while (tmp != ToBeDelete)
		{
			tmp = tmp->next;
		}

		tmp->next = NULL;
		delete ToBeDelete;
		ToBeDelete = NULL;
	}
}

做不到完美,也要做到近似完美。总体的时间复杂度为【O(N)*(N-1)+O(n)*1】/n,结果为O(n).

总结

连自己都看不太懂并且无法说服自己的代码,还怎么给别人看。我觉得优秀的编程就是写出来的程序能很容易的读懂,所以努力喽


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章