【问题标题】:Finding the pair of strings with most number of identical letters in an array查找数组中相同字母数量最多的字符串对
【发布时间】:2017-03-20 12:18:10
【问题描述】:

假设我有一个不同长度的字符串数组。
可以假设字符串没有重复字符。
使用蛮力算法,我可以在 n 平方时间内找到具有最多相同字母的字符串对(顺序无关紧要 - 例如,“ABCDZFW”和“FBZ”有 3 个相同的字母)。 有没有更有效的方法来做到这一点?

尝试:我试图想出一个使用 trie 数据结构的解决方案,但这不起作用,因为 trie 只会将具有相似前缀的字符串组合在一起。

【问题讨论】:

  • 用例是什么?还是这是作业?
  • 你的字符串的最大长度是多少?
  • 字符串是只包含大写字母还是什么?
  • 这不是家庭作业,也没有具体的用例。我只是好奇如何从算法上解决这类问题。是的,字符串仅由大写字母组成。字符串的最大长度为 26,因为没有字符重复。
  • @VictorKwon 请再次检查答案。我已经更正并扩展了答案。

标签: arrays string algorithm performance data-structures


【解决方案1】:

我可以找到具有最多相同数量的字符串对 字母(顺序无关紧要 - 例如,“ABCDZFW”和“FBZ”有 3 个相同的字母)在 n 平方时间内。

我认为你不能因为字符串比较本身是O(max(length(s1), length(s2))) 以及用于检查所有对的O(n^2) 循环。但是你可以在一定程度上优化字符串的比较。

正如您提到的,字符串没有重复项,根据您的输入,我假设字符串仅包含大写字母。因此,它变成了每个字符串只能是 26 个字符。

对于每个字符串,我们可以使用位掩码。并且对于字符串的每个字符,我们可以设置对应的位为1。例如:

ABCGH
11000111 (from LSB to MSB)

因此,我们为n 字符串提供了n 位掩码。

方式#1

现在您可以使用O(n^2) 循环检查所有可能的字符串对,并通过对两个相应的掩码进行与运算来比较字符串,并检查设置的位数(汉明权重)。显然这是对您的版本的改进,因为现在优化了字符串比较 - 只有两个 32 位整数之间的 AND 操作,即 O(1) 操作。

例如,对于任何两个字符串的比较将是:

ABCDG
ABCEF

X1 = mask(ABCDG) => 1001111
X2 = mask(ABCEF) => 0110111

X1 AND X2 => 0000111

hamming weight(0000111) => 3 // number of set bits

方式#2

现在,一个观察结果是相同类型位的 AND 为 1。因此,对于每个掩码,我们将尝试将两个字符串掩码的 AND 值的 Hamming weight(设置位总数)最大化为最多的字符串匹配的字符具有相同的位 1,对这两个掩码进行与运算将使这些位为 1。

现在构建一个带有所有掩码的 Trie - Trie 的每个节点都将根据相应的位是否设置而保持 0 或 1。从 MSB 到 LSB 插入每个掩码。在将ith 掩码插入 Trie 之前(已经持有i - 1 掩码),我们将查询尝试通过转到同一位的分支(使最终 AND 变量中的位 1)和 也到相反位的分支,因为在以后的级别中,您可能会在此分支中获得更多设置位

关于这个 Trie 部分,为了更好的图解解释,你可以找到一个类似的线程 here(这适用于 XOR)。

在最坏的情况下,我们将需要遍历 trie 的许多分支以最大化汉明权重。在最坏的情况下,大约需要6 * 10^6 操作(在典型机器中大约需要 1 秒),而且我们需要额外的空间来构建 trie。但是假设字符串的总数是10^5,那么对于O(n^2) 算法,它将需要太多的10^10 操作——所以trie 方法仍然要好得多。

如果您在实施方面遇到问题,请告诉我。不幸的是,只有当您是 C/C++ 或 Java 人员时,我才能帮助您编写代码。

感谢@JimMischel 指出一个重大缺陷。我首先稍微误解了这个说法。

【讨论】:

  • 我不认为xor 是最好的方法。如果你and 掩码,那么你就只有那些相同的位。然后您可以使用this bithack 之类的东西来查找您想要最大化 的设置位数。不管怎样,它仍然是一个 O(n^2) 算法。
  • @JimMischel 不,不是O(n^2)。在插入每个查询以最小化 XOR 的元素之前。如果字符串总数为n,则n 插入和查询将在N = n * 32 处渐近地花费O(N) 时间。您可以查看上面的链接。我可能是错的,但你能提到一个 XOR 不起作用的测试用例吗?
  • 我的立场是正确的。我误解了你的方法,并认为你是 xoring 每一个面具。我仍然不清楚 trie 如何帮助您找出 0111011111 具有三个共同位。我想我不明白异或查询步骤。我会更仔细地检查您的链接。
  • @JimMischel 感谢您的指出。是的,您对 XOR 的看法是正确的。我首先误解了这个说法。我现在编辑了答案。如果您有更好的想法,请查看并告诉我。
  • 你的第二种方法实际上只是一个26层的二叉树。确定共同设置位数的查询涉及穷举树搜索。虽然树搜索可能会产生更小的渐近时间(我并不完全相信这一点),但实际上执行(n^2)/2 AND 操作几乎肯定会比n 穷举树搜索更快。
猜你喜欢
  • 1970-01-01
  • 2022-06-12
  • 1970-01-01
  • 2016-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 1970-01-01
相关资源
最近更新 更多