【问题标题】:fast way for string comparison字符串比较的快速方法
【发布时间】:2015-03-28 20:40:46
【问题描述】:

我有一个简单的问题,但它让我感到困惑。

我有两个字符串,我想计算两者之间有多少不同的字符。字符串已排序,长度相等。不要拆分字符串。

例如

input:  abc, bcd
output: 2, because a and d are different characters

input:  abce, bccd
output: 4, because a, c, d and e are different.

我知道我可以在 O(N^2) 内完成,但是对于这些排序的字符串,我该如何在 O(N) 内解决呢?

只需要不同字符的个数,不需要指明是哪个数字。

【问题讨论】:

  • 两者都只是字母数字字符吗?因此,您可以制作这些字符的直方图(两个字符串的直方图分别)。然后只需比较零元素的直方图列。 (O(n) + O(n) + O(非常小的 m*m))
  • “我知道我可以在 O(N2) 内完成” 你是怎么做到的?您可能无法做到(是否已排序字符串)来捕捉所有差异。
  • @πάντα ῥεῖ “你是怎么做到的?”用手指。
  • @VladfromMoscow 你现在开玩笑而不是提供 LQ 问题的答案?嗯,你现在好像进步了。
  • @πάνταῥεῖ 嗯? Why not something like this?

标签: c++ string string-comparison


【解决方案1】:

我最初认为您需要一个相当复杂的算法,例如Smith-Waterman。但是对输入的限制使得在O(m + n) 中实现这一点相当容易,其中m 是第一个字符串的长度,n 是第二个字符串的长度。

我们可以使用内置算法来计算共同字符的数量,然后我们可以使用该信息来生成您要查找的数字:

#include <algorithm>
#include <iostream>
#include <string>

int main() {
    std::string m = "abce";
    std::string n = "bccd";
    std::string result;

    std::set_intersection(
            m.begin(), m.end(),
            n.begin(), n.end(),
            std::back_inserter(result));

    std::cout << m.size() + n.size() - 2 * result.size() << "\n";
}

在这种特殊情况下,它会根据需要输出4

【讨论】:

  • 如果你只需要数字,而不需要不同的字符,你可以写一个不需要内存分配的算法:coliru.stacked-crooked.com/a/909d1f4747991164
  • @dyp:当然。我们还可以编写一个输出迭代器,它只计算它增加了多少次。但是用两行代码解决这些问题还是很不错的。
【解决方案2】:

在看到答案真的很简单之后,感谢@Bill Lynch,我的解决方案可能太复杂了!无论如何,这是一个简单的计数差异。

#include <iostream>
#include <algorithm>
#include <array>

int main() {
    std::array<int,26> str1 = {};
    std::array<int,26> str2 = {};

    std::string s1("abce");
    std::string s2("bccd");


    for(char c : s1)
        ++str1[c-'a'];
    for(char c : s2)
        ++str2[c-'a'];

    int index = 0;

    std::cout << std::count_if(str1.begin(),str1.end(),[&](int x)
    {
        return x != str2[index++];
    });
}

它是O(n+m),除非我在分析中犯了错误。

【讨论】:

  • 哇,好点子。我怎么能放过它。谢谢!
  • 我确实注意到了,这就是我调用str1.fill(0)str2.fill(0) 的原因,但是是的,大括号初始化器更简洁。感谢您指出这一点。
【解决方案3】:

您可以使用dynamic programming 实现 O(n)。即使用整数d 来存储差异。

Algo:
move from lower index to higher index of both array.  
if a[i] not equal b[j]:
           increase d by 2
           move the index of smaller array and check again.
if a[i] is equal to b[j] : 
           decrease d by 1
           move both index
repeat this until reach the end of array

【讨论】:

    【解决方案4】:

    O(2n) 和 O(n) 完全一样,因为“O”表示方法成本的渐近行为。

    更新:我刚刚注意到你的意思是 O(n^2) 和你的 O(N2)。

    如果您需要进行比较,您将始终将 O(n^2) 作为成本,因为您必须:

    1) 循环为你的话的每个字符,这是 O(n)

    2) 比较每个单词中的当前字符,您必须使用包含已检查字符的临时列表。所以,这是另一个嵌套的 O(n)。

    所以,O(n) * O(n) = O(n^2)

    注意:您始终可以忽略 O 表达式中的数字系数,因为它无关紧要。

    【讨论】:

    • "O(2n)" OP 可能意味着 O(n^2)
    • @Sergio0694:正如在 cmets 和我的回答中看到的那样,您可以在少于 O(n^2) 的比较中解决这个问题。
    猜你喜欢
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-07
    相关资源
    最近更新 更多