查找散列映射中的所有键,例如作为查询子集的数据结构

时间:2018-03-20 21:40:25

标签: algorithm hashmap

问题

我们说我有一个HashMap:

{
  "foo" => (A,B),
  "bar" => (B,C),
  "baz" => (A,D)
}

我将其转换为其他数据结构,类似于:

{
  (A,B) => "foo",
  (B,C) => "bar",
  (A,D) => "baz",
  (D,E) => "biz"
}

鉴于'键' (或我认为是查询):(A,B,C)

我想查找其密钥是查询集子集的所有值:("foo","bar")

我试图找到一种有效的算法/数据结构来有效地进行查找,尽管我认为没有O(1)解决方案。

一种可能的解决方案

我有一个想法是将变换后的地图分解为:

{
  A => ("foo","baz"),
  B => ("foo","bar")
  C => ("bar"),
  D => ("baz","biz"),
  E => ("biz")
}

然后在查询集中查找中的每个元素:(D => ("baz", "biz"), E => ("biz"))

联盟他们:("baz", "biz")

从所有可能结果的集合中获取差异:("foo", "bar", "baz", "biz") - ("baz", "biz") => ("foo", "bar")

虽然这有效,但是有很多步骤,其中包含num_of_set_elements个数量的联合,而对于具有小查询的大型集合,可能会有大量的查找。

那么,有没有人有更好的解决方案?

1 个答案:

答案 0 :(得分:2)

基本解决方案不需要构建新结构:遍历对(键,值),如果值是目标的子集,则生成键。如果您可以使用64位整数(小于64个原子值ABC表示集合,则预期时间为O(n)(n =键数), ...)。例如,请参阅https://cs.calvin.edu/activities/books/c++/ds/2e/WebItems/Chapter09/Bitsets.pdf(如果A& S == S,则S包含A),如果必须以其他方式检查潜在子集,还需要更多。

但是如果你有足够的空间和很长的时间来预处理数据,那么有一个(疯狂?)摊销的O(1)时间解决方案用于查找。 如果S是所有可能原子值(AB,...)的集合,则可以构建每个值的所有可能超集((A, B),{ {1}},...)是(A, C)的子集。 现在你可以像这样构建一个新的地图(伪代码):

S

查找将以恒定的摊销时间O(1)进行。地图将大约有for each pair (key, value): for every superset s of value: add key to m[s] 个键。值的大小取决于键的大小,例如最大的键2^|S|将包含初始映射的每个键。预处理将类似O(n * 2 ^ | S |)。

我宁愿去O(n)。