数据结构插入,删除,模式

时间:2014-03-10 07:42:03

标签: data-structures

以下是访谈问题:为一系列整数设计数据结构{1,...,M}(数字可以重复)支持insert(x),delete(x)和返回模式,返回最多经常编号。

面试官说我们可以在O(1)中进行O(M)中预处理的所有操作。他还接受我可以在O(log(n))中执行insert(x)和delete(x),在O(1)中使用O(M)中的预处理进行返回模式。

但是我只能在O(n)中给出插入(x)和删除(x)以及在O(1)中返回模式,实际上我怎么能给O(log(n))或/和O(1) )在插入(x)和删除(x)中,并在O(1)中返回模式,并在O(M)中预处理?

2 个答案:

答案 0 :(得分:1)

当您听到O(log X)操作时,首先想到的结构应该是binary search treeheap。供参考:(因为我专注于下面的一堆)

  

堆是一种专门的基于树的数据结构,它满足堆属性:如果A是B的父节点,那么节点A的密钥是相对于节点B的密钥排序的,具有相同的排序。堆。 ...父节点的密钥总是大于或等于子节点的密钥,最高密钥在根节点中(这种堆称为最大堆)....

二进制搜索树不允许在O(M)中构造(来自未排序的数据),所以让我们看看我们是否可以使堆工作(你可以在O(M)中创建一个堆)。

显然,我们希望最常见的数字位于顶部,因此这个堆需要使用频率作为其排序。

但是这给我们带来了一个问题 - insert(x)delete(x)都要求我们查看整个堆以找到正确的元素。

现在你应该考虑“如果我们在树中从索引到位置有某种映射?”,这正是我们将要拥有的。如果所有/大多数M元素都存在,我们可以只有一个数组,每个索引i的元素是指向堆中节点的指针。如果正确实现,这将允许我们在O(1)中查找堆节点,然后我们可以对其进行适当修改,然后移动O(log M)同时insertdelete

如果只存在少数M元素,则用(hash-)映射(整数到堆节点)替换数组可能是个好主意。

返回该模式需要O(1)


所有操作的

O(1)肯定要困难得多。

我想到了以下结构:

3     2
^     ^
|     |         
5     7     4     1

12    14    15    18

要解释这里发生了什么 - 12141518对应频率,上面的数字对应于具有所述频率的元素,因此,53的频率均为1272的频率为14等。

这可以实现为双链表:

          /-------\                     /-------\
(12) <-> 5 <-> 3 <-> (13) <-> (14) <-> 7 <-> 2 <-> (15) <-> 4 <-> (16) <-> (18) <-> 1
  ^------------------/ ^------/ ^------------------/ ^------------/ ^------/

您可能会注意到:

我填写了遗失的1316 - 这些是必要的,否则我们必须在执行insert时更新频率相同的所有元素(在此示例中,在执行5时,您需要更新13以指向insert(3),因为13尚不存在,所以它会指向{ {1}})。

我跳过14 - 这只是空间使用方面的优化 - 这使得此结构占用17空间,而不是O(M)。跳过一个数字的确切条件就是它在频率上没有任何元素,或者比其频率少一个元素。

链接列表上方发生了一些奇怪的事情。这些只是意味着O(M + MaxFrequency)也指向513也指向7,即每个元素也保留指向下一个频率的指针。

链接列表下面发生了一些奇怪的事情。这些只是意味着每个频率保持指向它之前的频率的指针(这比每个元素保持指向它自己和下一个频率的指针更节省空间。)

与上述解决方案类似,我们在此结构中保留整数到节点的映射(数组或映射)。

要插入:

  • 通过映射查找节点。
  • 删除节点。
  • 获取指向下一个频率的指针,将其插入该节点之后。
  • 使用插入位置之后的元素设置下一个频率指针(或者是下一个频率,在这种情况下我们可以使指针指向该指针,否则我们可以使下一个频率指针指向同一元素该元素的下一个频率指针)。

要删除:

  • 通过映射查找节点。
  • 删除节点。
  • 通过下一个频率获取指向当前频率的指针,将其插入该节点之前。
  • 设置指向该节点的下一个频率指针。

获得模式:

返回最后一个节点。

答案 1 :(得分:0)

由于范围是固定的,为简单起见,我们举个例子M = 7(范围是1到7)。所以我们需要最多3位来表示每个数字。

0 - 000 1 - 001 2 - 010 3 - 011 4 - 100 5 - 101 6 - 110 7 - 111

现在创建一个b树,每个节点都有2个子节点(如Huffmann编码算法)。每个叶子将包含每个数字的频率(最初它将为0)。这些节点的地址将保存在一个数组中,键作为索引(即节点1的地址将在数组中的索引1处)。

通过预处理,我们可以在O(M)时间内执行插入,删除O(1),模式。

  1. insert(x) - 转到数组中的位置k,获取该节点的节点地址和增量计数器。
  2. delete(x) - 如上所述,只要递减计数器,如果&gt; 0。
  3. 模式 - 在数组中线性搜索最大频率(计数器值)。