【问题标题】:Hash Table and Substring Matching哈希表和子串匹配
【发布时间】:2012-05-18 18:49:34
【问题描述】:

我有数百个键,例如:

  • 红苹果
  • maninred
  • 论坛
  • 蓝苹果

我有与这些键相关的数据,数据是一个字符串,最后有相关的键。

  • 红苹果:树有红苹果
  • maninred: she-saw-the-maninred
  • foraman:他们买了现在的foraman
  • blueapple:它令人惊讶,但它是一个蓝苹果

我希望使用哈希表和哈希函数根据键记录数据,并且我希望能够从表中检索数据。

我知道使用哈希函数和哈希表,这里没有问题。

但是;

我希望给程序一个字符串,它作为子字符串发生并检索匹配键的数据。

例如:

我必须给“红色”并且必须能够得到

  • 红苹果:树有红苹果
  • maninred: she-saw-the-maninred

作为输出。

我必须给“苹果”并且必须能够得到

  • 红苹果:树有红苹果
  • blueapple:它令人惊讶,但它是一个蓝苹果

作为输出。

我只能考虑搜索所有具有匹配子字符串的键,还有其他解决方案吗?如果我搜索每个查询的所有关键字符串,则不需要使用散列,没有意义,是吗?

但是,搜索所有子字符串的键是O(N),我希望用O(1)解决这个问题。

通过散列,我可以散列一个键,例如“红苹果”到例如943,以及“maninred”,例如332

查询人给出字符串“red”我如何从 943332 中找出键具有“red”子字符串?这超出了我的 cs 思维能力。

感谢您的任何建议,想法。

【问题讨论】:

  • 为什么你“期望使用哈希表”?后缀树会更合适。
  • 另外,我相信你不能在O(1) 中这样做,因为对于字符串""(空字符串),你将不得不输出整个集合。另外,在谈到字符串时,读取字符串通常被视为O(|S|) 而不是O(1)
  • @amit 如果子字符串位于键的中间,后缀树会有所帮助吗?
  • 感谢回复,考虑字符串内部的操作时间不是第一个问题。 @deathApril 是的,这是一个家庭作业,但我不想要解决方案。我想知道问q是否正确。 我只是想知道我应该在所有字符串中搜索给定的子字符串(查询参数/搜索输入),还是像预言机一样预测哈希码是否告诉我他们的关键字符串具有子字符串
  • @AdamMatan: 当然会 - 如果有一个字符串 s 表示 ts 的子字符串,那么 t 将是前缀 - 是 @987654329 的某些后缀@。您可以通过遍历树轻松发现它。

标签: algorithm hashtable


【解决方案1】:

您可能应该对 n-gramm 使用反转索引,同样的方法用于拼写校正。对于单词 redapple,您将有以下一组 3-gramms red、eda、dap、app、ppl、ple。对于每个 n-gramm,您将有一个包含它的字符串列表。例如对于红色,它将是

red -> maninred, redapple

此列表中的单词必须排序。当您想查找包含给定子字符串的所有字符串时,您可以在 n-gramm 上搜索子字符串并截取 n-gramm 的单词列表。

这个算法不是 O(n),但它练习它有足够的速度。

【讨论】:

  • 非常感谢您的详细回答,我了解您详细说明了我的问题中的第一选择,我必须遍历给定输入的所有单词列表。对于搜索输入,我必须查看每个单词的 n-gram。我没听错吗?
  • 请注意,所有 n-gram 的列表是 O(n^2) 空格,它会使每个 insert()remove() op 至少慢 O(logn),因为相关应该首先找到索引中的位置。
  • 嘿,请有人回答我,没有机会不在键列表中查找具有输入子字符串的单词,对吗?我只是想知道是否有一种神奇的方法可以仅查看输入搜索子字符串来预测键的哈希码?
  • 或者有没有办法编写一个神奇的哈希函数,当我给它输入搜索子字符串时,它会告诉我其中包含子字符串的键的位置?
  • tuxi 第一个问题是的,首先你应该建立单词的索引。当您可能搜索时,您可以使用最小的集合并仅对其进行迭代或对列表交集使用相同的特殊算法。
【解决方案2】:

它不能在哈希表中很好地完成。给定一个子字符串 - 您无法预测整个字符串的散列结果1

一个合理的选择是使用suffix tree。后缀树中的每个终端都将保存完整字符串的引用列表,该后缀与之相关。

给定一个子字符串t,如果它确实是您的集合中某个s 的子字符串,那么s 有一个后缀x - 这样t 就是x 的前缀.通过在读取t 时遍历后缀树,并找到从您到达的节点可到达的所有终端。这些终端包含所有需要的字符串。


(1)假设合理的hash函数,如果hashCode() == 0为每个元素,显然可以预测出hash值。

【讨论】:

  • 后缀数组是更好的解决方案。您也可以使用哈希表来做到这一点,但是通过将所有子字符串的索引设置到一定长度,它们变得几乎是唯一的,类似于接受的答案中的建议。
【解决方案3】:

我最近研究了这个问题,我确信这是做不到的。我希望哈希表能像你一样帮助我提高搜索速度,但这让我很失望。

【讨论】:

  • 这是可以做到的,这是公认的答案。您为所有子字符串或可能只是您感兴趣的 n-gram 创建索引。然后查找该索引。但只有坚持使用哈希表,后缀数组才更合适。
  • 那太复杂了。一张表有大约 100 万条记录,我将有数百万条子串,这很糟糕。
  • 数百万个子串只有几兆字节,你知道吗?
  • 我的错,我会研究这个问题
猜你喜欢
  • 1970-01-01
  • 2021-04-23
  • 2022-07-06
  • 2019-10-10
  • 1970-01-01
  • 2020-12-08
  • 1970-01-01
  • 2011-07-14
相关资源
最近更新 更多