我可以找到具有最多相同数量的字符串对
字母(顺序无关紧要 - 例如,“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 指出一个重大缺陷。我首先稍微误解了这个说法。