我是DS和算法的新手,最近在求职面试中,我被问到有关性能调优和代码的问题。我们有一个包含数十亿条目的数据结构,我们需要搜索该数据结构中的特定单词。那么我们可以使用哪个Java特性/库在最快的时间内进行搜索?
当场我无法想到确切的答案所以我写了:
我如何理解这个问题的确切答案以及最佳解决方案是什么?
答案 0 :(得分:2)
在阅读问题并在评论中得到澄清后,我认为对我来说显而易见的是:您需要提出后续问题。
我会尝试将其分解并提供我希望会有所帮助的评论,因为我也知道它是什么样的"当下"当你最不需要它时,神经会如何刺伤你。
我们有一个包含数十亿条目的数据结构,我们需要搜索该数据结构中的特定单词。
我认为这里有一个很好的后续问题:
问: 特定的数据结构用于包含所有这些数据?
我会按,直到他们给我一个实际名称并解释为什么不能命名Java算法/库。众所周知,数据结构可能是String[]
,Set<String>
,甚至是磁盘上文件的奇特名称(如果他们试图让你失望) 。他们也可以澄清并说DS不相关,你可以选择你认为最好的DS。
措辞也暗示他们实现了结构,并且它已经填充在一个系统中,可能有足够的内存来容纳所有结构。要求确认这真的,这个案例可以为您提供有用的信息。
例如:&#34;基于措辞,似乎这个神秘的数据结构已经实现并且在具有足够内存的系统中完全填充在内存中。你能证实我的理解是正确的吗?如果没有,你能进一步澄清吗?&#34;
鉴于建议的措辞,以及我们没有进一步澄清的事实,我将假设,为了这个答案的目的,我的假设确实是正确的。
请注意 如果 ,您被要求设计数据结构以保存所有这些信息,您会有提出非常不同的问题,考虑内存约束,甚至可能询问字符集/编码(例如ASCII与多字节Unicode)。
此外,如果您被要求设计搜索算法,那么知道DS是先决条件,并且不知道这可能使任务无法完成。例如,如果您正在处理数组与二进制搜索树,则二进制搜索算法实现将看起来非常不同,即使两者都提供 O(lg n)时间复杂度。
那么我们可以使用哪个java特性/库在最快的时间内进行搜索?
与第1部分一致,此问题仅询问您将选择执行搜索的预先存在/内置Java代码。 &#34;最快的时间&#34;这里应该让你考虑 O(1)中的解决方案,即是恒定时间。但是,数据结构可能会为您打开/关闭门。
Java中的一些搜索算法适用于泛型,而其他搜索算法适用于其他类型(如数组)。某些算法适用于Map
s,而其他算法适用于List
s,Set
s,依此类推。第一部分的后续问题可以帮助回答这个问题。
尽管如此,即使您知道DS,但当时也无法想到特定的方法名称,我也认为提及界面或至少相关的包装应该被认为是合理的。如果您需要更加专业的话,可以在Java文档中检查更多详细信息,因为首先要了解它的用途。< / p>
我们可以将值存储在地图中并搜索地图中的单词(但是如何决定地图中的键值对会遇到困难。)
考虑到措辞,我对他们问题的解释是不&#34;您将使用哪种数据结构?&#34;,而是&#34;预先存在的搜索算法你会选择吗?&#34;。在我看来,他们需要回答关于DS的问题。
那就是说,如果你确实被问过&#34;你会使用哪种数据结构?&#34;,那么Map
仍会对你不利,因为你没有&#39 ; t确实需要映射一个值的键。您只需要存储一个值(即单词)。因此,Set
,特别是HashSet
,会成为更好的候选者,因为它也避免重复,并且应该在过程中消耗更少的内存,因为它存储奇异值,而不是键/价值对。
当然,这仍然是我之前提出的假设。如果说存储器限制是一个问题,那么水平扩展到多个服务器等等可能是必要的。
我如何理解这个问题的确切答案以及最佳解决方案是什么?
可能可能他们希望看到你是否会跟进问题,因为他们没有提供给你的信息。
答案 1 :(得分:1)
有一些数据结构允许高效搜索,假设内存需求不是问题且数据结构已经填充。
关于时间复杂度,Set#contains
和Map#containsKey
都是O(1)
,假设哈希函数并不昂贵且碰撞次数不多。
因为数据结构存储了单词(假设你指的是String
),那么使用http://formyip.com(基数树,前缀树等)也可能相对有效,这将允许您按字符搜索(我相信将O(log n)
)。如果哈希函数很昂贵或者存在很多冲突,那么这可能是一个很好的选择!
你给面试官的答案应该足够了,因为哈希是一种有效的搜索方法,即使是数十亿条目也是如此。
答案 2 :(得分:0)
您没有提及条目是文字还是文件(多个单词)。在这两种情况下,search index都适合。
搜索索引从十亿个文档条目中提取单词,并将这些单词的地图管理到它们所使用的文档中。像Lucene这样的框架(例如,作为SOLR或ElasticSearch的一部分)为您管理内存和持久性。
如果它只是成千上万个条目中的一个,那么简单的HashMap就足够了,因为那时就不需要内存管理了。如果所有十亿条目都是单个单词,那么数据库可能是更好的选择。
答案 3 :(得分:0)
如其他人所说,hashmap解决方案是合理的,但是在可伸缩性方面存在疑问。
以下是该问题的可能解决方案,如下文所述
子字符串匹配如果您的条目blob是单个sting或单词(没有任何空格),则需要在其中搜索任意子字符串。在这种情况下,您需要解析每个条目以找到匹配的最佳条目。一个人使用像Boyer Moor算法这样的算法。有关详细信息,请参阅this和this。这也等同于grep - 因为grep在
索引搜索。在这里,您假设条目包含一组单词,搜索仅限于固定的单词长度。在这种情况下,条目将被索引所有可能出现的单词。这通常称为“全文搜索”。有许多算法可以做到这一点,以及可以直接使用的开源项目数量。他们中的许多人还支持通配符搜索,近似搜索等,如下所示: 一个。 Apache Lucene:http://lucene.apache.org/java/docs/index.html 湾OpenFTS:http://openfts.sourceforge.net/ C。狮身人面像http://sphinxsearch.com/
最有可能的是,如果你需要“固定词”作为查询,那么方法二将非常快速有效
答案 4 :(得分:-2)
数十亿个条目位于可能存储在主存储器中的边缘(例如,以每个条目100个字节存储100亿个条目将占用1000 GB主存储器)。
虽然将数据存储在主内存中可提供非常高的吞吐量(每秒数千到数百万个请求),但您可能需要特殊硬件(典型刀片服务器仅提供16 GB,但有商用服务器允许安装高达3000 GB的主内存)。此外,在Java堆中保留这么多数据可能会导致垃圾收集器暂停几秒或几分钟,除非特别小心。
因此,除非您的数据结构在主内存中承认非常紧凑的表示(例如,您只需要在int中进行成员资格检查,这可能是512 MB Bitset),否则您不想存储它在主内存中,但在磁盘上。
因此,您需要持久性。任何关系或NoSQL数据库都允许按键进行有效搜索,并且可以轻松处理这些数据量。要与关系数据库通信,请使用JPA或JDBC。要与非关系数据库通信,您可以使用其专有的Java API或抽象层,例如Spring Data。
如果您愿意,也可以从头开始实施持久性(即面试官要求)。为在外部存储器中高效查找而优化的数据结构是B-Tree,这是许多数据库在内部使用的内容: - )