如标题所述,我需要定义一个数据结构,只需O(1)时间进行插入删除和getMIn时间....没有空间限制.....
我搜索了SO的相同,我发现的所有内容都是在O(1)时间插入和删除....即使是堆栈也是如此。我看到上一篇文章在堆栈溢出中他们所说的就是哈希......
我在O(1)时间内对getMIn进行了分析,我们可以使用堆数据结构 为了在O(1)时间插入和删除我们有堆栈......
所以为了实现我的目标,我认为我需要调整heapdatastructure和stack ... 我将如何在这种情况下添加散列技术...
如果我使用哈希表,那么我的哈希函数应该如何分析哈希方面的情况...任何好的参考将被赞赏...
答案 0 :(得分:2)
如果您最初假设插入和删除是O(1)复杂性(如果您只想插入顶部并从顶部删除/弹出然后堆栈工作正常)那么为了让getMin返回在某种程度上你需要以恒定时间存储最小值的最小值。如果你只是有一个成员变量跟踪min,那么如果它被从堆栈中删除会发生什么?您需要下一个最小值,或相对于堆栈中剩余的最小值。要做到这一点,你可以让你的元素在一个堆栈中包含它认为最小的元素。堆栈在代码中由链表表示,因此链表中节点的结构看起来像这样:
struct Node
{
int value;
int min;
Node *next;
}
如果您查看示例列表:7-&gt; 3-&gt; 1-&gt; 5-&gt; 2。让我们来看看如何构建它。首先你输入值2(到空堆栈),这是min,因为它是第一个数字,跟踪它并在构造它时将它添加到节点:{2,2}。然后你将5推到堆栈上,5> 2,所以min是相同的推动{5,2},现在你有{5,2} - &gt; {2,2}。然后你按1英寸,1 <2,所以新的分钟是1,按{1,1},现在它是{1,1} - &gt; {5,2} - &gt; {2,2}等等到最后你有:
{7,1} - GT; {3,1} - GT; {1,1} - GT; {5,2} - GT; {2,2}
在这个实现中,如果你弹出7,3和1你的新分钟将是2应该是。并且您的所有操作仍处于持续时间,因为您只是向节点添加了比较和另一个值。 (你可以使用类似C ++的peek()或只是使用指向列表顶部的指针来查看堆栈的顶部并抓住那里的min,它会给出你在恒定时间内的堆栈最小值。
这种实现的权衡是你的节点中有一个额外的整数,如果你在一个非常大的列表中只有一两分钟,那就浪费了内存。如果是这种情况,那么您可以在单独的堆栈中跟踪分钟,只需将您要删除的节点的值与此列表的顶部进行比较,如果匹配则将其从两个列表中删除。要记住更多的事情,所以这取决于具体情况。
免责声明:这是我在这个论坛的第一篇文章,所以如果它有点令人费解或罗嗦,我很抱歉。我也没有说这是&#34;一个真正的答案&#34;但它是我认为最简单的并且符合问题要求的那个。总是存在权衡取决于具体情况,需要采用不同的方法。答案 1 :(得分:2)
这是一个设计问题,这意味着他们希望看到您可以多快地扩充现有的数据结构。
从你所知道的开始:
hashtable
在这里,我提出了一种方法。你可能会找到你喜欢的其他东西。
main
,在哪里存储所有元素mins
跟踪最小值。main
时,也将其添加到mins
。mins
地图头部的值,请使用等效于addToHead
的内容将其添加到地图中。main
中删除元素时,也会将其从mins
中删除。 2 * O(1)= O(1)getMin
只是偷看而不删除。所以只要看看mins
。编辑:
(感谢@Andrew Tomazos - Fathomling,让我们有更多乐趣!)
我们都知道插入哈希表的成本是O(1)。但事实上,如果你曾经构建过一个哈希表,你就知道必须保持表的大小加倍以避免溢出。每次将具有n个元素的表的大小加倍时,必须重新插入元素,然后添加新元素。通过这种分析,它会
似乎在哈希表中添加元素的最坏情况成本是O(n)。那么为什么我们说它是O(1)?因为并非所有元素都是最坏的情况!实际上,只有出现加倍的元素才会出现最坏情况。因此,插入n个元素需n+summation(2^i where i=0 to lg(n-1))
,这会n+2n = O(n)
,因此O(n)/n = O(1)
!!!
为什么不将相同的原则应用于linkedHashMap?无论如何你必须重新加载所有元素!因此,每当您将main
加倍时,将main
中的所有元素也放入分钟,并在mins
中对它们进行排序。然后对于所有其他情况按上述步骤进行(子弹步骤)。
答案 2 :(得分:0)
散列表允许您在O(1)中插入和删除(堆栈不是因为您不能在堆栈中有孔)。但是你也不能在O(1)中使用getMin,因为排序你的元素不能比O(n * Log(n))(它是theorem)快,这意味着O(Log(n) ))每个元素。
你可以保持指向min的指针,使得getMin在O(1)中。这个指针可以很容易地更新插入,但不能删除min。但根据您使用删除的频率,这可能是一个好主意。
答案 3 :(得分:0)
严格地说,你所说的问题实际上是不可能的,但请考虑以下因素:
给定类型T对该类型的所有可能元素进行枚举,使得值i小于值j iff T(i)&lt; T(j)的。 (即按顺序编号T类型的所有可能值)
创建该大小的数组。
制作数组的元素:
struct PT
{
T t;
PT* next_higher;
PT* prev_lower;
}
在数组中插入和删除元素,维护双链表(按索引顺序,因此按顺序排序)存储
这将为您提供常量getMin和delete。
对于插入,你需要在常量时间内找到数组中的下一个元素,所以我会使用一种基数搜索。
如果数组的大小是2 ^ x则保持x“跳过”数组,其中数组i的元素j指向要索引的主数组的最近元素(j <&lt;&lt; i)。
然后,这将始终需要固定的x次查找来更新和搜索,这样可以提供恒定的时间插入。
这使用了指数空间,但问题的要求允许这样做。
答案 4 :(得分:0)
您可以使用 trie 。 trie对于插入,删除和getmin都具有O(L)复杂度,其中L是您正在寻找的字符串(或其他)的长度。对于n(元素数量),它具有恒定的复杂性。
但它需要大量内存。由于他们强调“没有空间限制”,他们可能正在考虑一个特里。 :d
答案 5 :(得分:-1)
在您的问题陈述中“插入和删除O(1)时间我们有堆栈......” 所以我假设删除= pop() 在这种情况下,使用另一个堆栈来跟踪最小值
ALGO: 堆栈1 - 正常堆栈;堆栈2 - 最小堆栈
推送到堆栈1。 如果堆栈2为空或新项目&lt; stack2.peek(),也推送到堆栈2
目标:在任何时候,stack2.peek()应该给你min O(1)
pop()。 如果popped元素等于stack2.peek(),则来自堆栈2的pop()