【问题标题】:Using a Dictionary find a list of all possible words that could be the original string使用字典查找可能是原始字符串的所有可能单词的列表
【发布时间】:2016-05-27 16:01:41
【问题描述】:

我的朋友在一次采访中提出了这个问题。虽然他不记得这个问题的一字不差,但他还是尽其所能地回忆了下面的内容。

一个字符串(一个单词)从发送者发送到接收者。在传输过程中,字符串的一个字母被改变。使用字典查找可能是原始字符串的所有可能单词的列表。您不知道原始字符串是什么,您只能访问收到的字符串和字典。

第一次看到这个问题时,我想到的第一件事是迭代替换字符串中的所有字符,然后将它们与字典中的单词进行比较。如果有匹配项,那么我会将该单词存储在一个数组中。(假设不区分大小写)

例如:

原词:猫

收到的单词:bat

我的算法:

遍历字典,将 OriginalWord.length() 的所有单词放入一个 HashTable 中

[a-z]at.....检查这些是否在哈希表中

b[a-z]t....检查这些是否在 hashTable 中

ba[a-z]....检查这些是否在 hashTable 中

朋友说这是他用的算法,但是面试官说没有优化。我一直在对这个问题进行一些研究,虽然我发现没有一个完全喜欢它。我发现了一些参考 Levenshtein 距离的东西。我对高级算法的了解有限,所以我无法理解它。此外,由于我无法联系面试官,因此我无法回答具体细节(例如,是否允许对字典进行预处理,在某某场景中会发生什么等……)。尽可能解释问题并做出合理的假设。

假设允许对字典进行预处理。在这种情况下问面试官什么问题比较好?有什么更好/更优化的算法可以用来解决这个问题?

【问题讨论】:

  • I have found some that make reference to Levenshtein distance. My knowledge of advanced algorithms is limited so I wasn't able to understand it. 这不是高级算法,它是动态编程的教科书示例,这是您在工作面试中应该知道的标准技术。
  • 另外,在时间复杂度、levenshtein 距离或接近变量方面,将花费O(n^2) 时间,与此方法相同,假设字典字符串和输入字符串的长度均为n ( levenshtein 距离会有更好的常数)

标签: string algorithm data-structures


【解决方案1】:

如果您允许通过创建automaton 对字典进行预处理,则可以在线性时间内解决。

首先创建一个自动机来决定一个字符串是否在字典中。 Aho Corasick 是创建此类自动机的算法示例之一。 trie 也基本上在做同样的事情(虽然效率较低)

复制这个自动机,你现在有两个自动机,Q1,Q2。开始状态在 Q1,结束状态在 Q2。通过从 Q1 中的每个状态到 Q2 中的下一个状态添加一个不确定的步骤来连接自动机,但具有不同的字符。

例如,如果您有状态:

A---a-->B

添加:

A--b-->B'. A--c-->B', ...., A--z-->B'

其中 A,B 是 Q1 中的状态,B' 是与 B 等效的状态 - 但在 Q2 中。

这允许您通过进入 Q2 来忽略一个错误(然后您不能再忽略任何错误)。

自动机创建完成后(并处理回确定性自动机),在查询时,您将在线性时间内获得匹配。

【讨论】:

  • 感谢您的回答!您引用的链接包含许多有用的信息。不过,您不必在其他评论中如此刻薄。
  • @LekanOsagie 抱歉,如果你被冒犯了,那不是我的本意。但是,对于面试,您需要了解一些特定的事情。如果在你职业生涯的早期就知道他们还为时过早,而且你还没有到那里,那也没关系 - 但你不能指望在没有适当背景的情况下能够理解高级面试问题。
  • 一个有趣的解决方案。 Q2 自动机非常昂贵,但非常有效。
  • @JimMischel 如果从非确定性切换回确定性会很昂贵,否则它是“唯一”加倍空间指纹。如果您将其保持为非确定性,则它是您答案的概括(用 trie 实现它,您会得到几乎相同的东西)。
【解决方案2】:

您可以通过从字典中创建一个 trie 来做到这一点。但不是以正常方式搜索它,而是进行通配符搜索。使用您的示例,给定字符串“bat”,您搜索“*at”。因此,对于 trie 中的每个顶级节点,您都会查找以“at”结尾的 3 个字母的单词。

然后你搜索“b*t”。也就是说,您转到顶级节点“b”,对于“b”之后的每个字符,搜索“t”作为下一个字母。

最后,您搜索“ba*”。也就是说,对于前缀“ba”,您要查找下一个字符是 't'。

假设字母 a-z,其最大复杂度为 26*n,其中 n 是单词中的字符数。实际上,它可能会少得多,因为并非所有角色都处于所有级别。例如,您不会找到以“bz”或“bq”开头的英语单词。

这行得通,但我似乎记得你可以用suffix tree 更有效地做到这一点。

【讨论】:

    猜你喜欢
    • 2015-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 2016-04-06
    • 2013-09-26
    • 1970-01-01
    相关资源
    最近更新 更多