【问题标题】:Find out the common parts of all the strings找出所有字符串的共同部分
【发布时间】:2014-07-15 13:02:56
【问题描述】:

我有一个大数组有将近 10000 个字符串,我想在这些字符串中找到所有公共部分(超过 3 个字符)并获取这些部分的出现。

我用 javascript 的简单方法实现,但它确实花费了很多时间,即使我对此做了一些优化,对于 1000 个字符串的短数组,Firefox 大约需要 8 秒,Chrome 大约需要 12 秒。

所以我想知道是否有任何相关的技术或算法,因为我认为这确实是一个普遍的问题,可以在许多应用程序中提出。

【问题讨论】:

  • 获取所有序列的所有常见出现 3 个或更大字母是常见问题吗?也许你需要描述你想用这些数据做什么。我有一种感觉,您可能已经决定了解决问题的错误方法。
  • 你可以研究一下打包器的工作原理,它非常快,但它也依赖于单词边界,而不仅仅是任何 3 个字符......
  • 你的意思是一个共同的prefix,一个共同的substring,或者可能是几个substrings?
  • 嗨,@cookiemonster 这些字符串大多不是短的(超过 15 甚至 30 个字符),通过找出它们,然后我可以替换它们,突出显示它们等。
  • 缓存是一个选项吗?

标签: javascript string algorithm search match


【解决方案1】:

我有一个稍微不同的问题,我需要找到每个单词的公共前缀,而不仅仅是可能位于单词中间或末尾的公共子字符串。此函数将返回一组单词的公共前缀。

        function findCommonPrefixes (words, min) {
            const result = new Set();
            for (const word of words) {
                let partial = word.toLowerCase();
                do {
                    const otherWords = words.filter(w => w !== word).map(w => w.toLowerCase());
                    for (const word of otherWords) {
                        if (word.includes(partial)) {
                            result.add(partial);
                            partial = '';
                            break;
                        }
                    }
                    if (partial) {
                        partial = partial.slice(0, (partial.length - 1))
                    }
                } while (partial.length && partial.length >= min)
            }
            return Array.from(result);
        }

【讨论】:

    【解决方案2】:

    构建一个包含所有可能子字符串的数组,对它们进行排序,然后查找连续相等的字符串块。

    下面的实现会查找特定长度的后缀并强制进行最少数量的匹配。目前尚不清楚您到底想要什么,但您需要一些限制。寻找最长的常用后缀很容易,但如果你只想要常用后缀,那是什么意思? 4 个字符的字符串出现 20 次是否优于 5 个字符的字符串出现 10 次?

    另外,请注意下面的代码不检查重叠字符串。如果您查找长度为 4 的匹配项,并且其中包含 30 个带有 "green" 的单词,则结果将同时包含 "gree""reen"

    它可能不是你想要的,但它应该很容易适应。而且速度相当快。在 10,000 个随机生成的字符串中,每个字符串大约有 30 个字符,查找长度为 10 的公共子字符串需要不到一秒的时间,而对于 1000,000 个字符串,可能需要 4 秒。

    不管怎样,这里是:

    /*
     *      Return an array of all substrings of the given length
     *      that occur at least mincount times in all the strings in
     *      the input array strings.
     */
    function substrings(strings, length, mincount) {
        var suffix = [];
        var res = [];
    
        for (var i = 0; i < strings.length; i++) {
            var s = strings[i];
    
            for (var j = 0; j < s.length - length + 1; j++) {
                suffix.push(s.substr(j, length));
            }
        }
    
        suffix.sort();
        suffix.push("");
    
        var last = "";
        var count = 1;
        for (var i = 0; i < suffix.length; i++) {
            var s = suffix[i];
    
            if (s == last) {
                count++;
            } else {
                if (count >= mincount) res.push(last);
                count = 1;
            }
            last = s;
        }
    
        return res;
    }
    

    【讨论】:

    • 我将此方法适用于所有子字符串(不仅是后缀,minLength为4,最小出现次数为5),处理10,000个字符串(总共4s)更快,我认为speed为O(n∑k +n),其中n表示字符串的个数,k表示每个字符串的长度。
    • @Haven 你能分享你的版本吗?谢谢
    • @Noitidart 嘿,这已经是老问题了,我现在已经解决了这个问题,检查一下here
    • 感谢@Haven 的评论,只是我需要做同样的事情,所以希望看到代码:)
    【解决方案3】:

    查看 Crossfilter http://square.github.io/crossfilter/ 它会做任何你想要的 map-reduce。不过,Javascript 在搜索大杂烩时可能会非常慢。根据您的限制,以及这 10,000 个字符串将如何随着时间的推移而增长,您可能会想到 RDMS,例如 MySQL,因为它们是为此类事物设计的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-26
      • 2016-04-20
      • 1970-01-01
      • 2012-10-12
      相关资源
      最近更新 更多