快速查找两个字符串是否具有共同字符的方法

时间:2013-12-19 07:20:01

标签: javascript string comparison

我有各种字符串比较和差异算法,但在某些时候,在我应用它们之前,我想找到两个字符串是否至少有一个共同的字符。这样我就可以跳过更复杂的功能。所以我需要一个非常快速的JavaScript函数来查找字符串A和字符串B是否至少有一个公共字符。

首先,我想为字符串A创建一个字符映射,然后检查字符串B中的每个字符对照该映射,直到找到某些内容。但后来我才意识到,如果两个字符串都很大并且它们有一个共同的第一个字符,那么为字符串A创建一个完整的映射效率会很低。

更新:有人回答使用indexOf(),这让我感到困惑。也许短语"有共同的特征"意思是"字符串是另一个"的子字符串?让我举一个我想要的例子:

例如,JavaScriptStop and stay共有一个字符S。其他示例是please look rightbreak the ice,它们共有一个字符k

9 个答案:

答案 0 :(得分:3)

如果您担心两次搜索相同字符的开销(可能是最小的),则可以创建已检查字符的缓存。像这个功能的东西可能适合这个法案:

var common_char = function(str1, str2) {
    var map = {};
    return Array.prototype.some.call(str1, function(c) {
        if( !map[c] && str2.indexOf(c) >= 0 ) {//character c not checked and in str2
            return true;
        }
        map[c] = true;
    });
}

答案 1 :(得分:3)

最简单的方法是循环遍历一个字符串中的每个字母,看看另一个字母是否包含任何单个字母。

除非按字母顺序对字符串进行排序,否则你不可能比查阅每个字母更有效率。

function anythingInCommon(a, b){
    if( b.length < a.length )
        return anythingInCommon(b, a)

    for( var i = 0, len = a.length; i < len; i++ ) 
        if(b.indexOf(a[i]) != -1)
            return true;
  
    return false
}

console.log(
  anythingInCommon("aaaaaaaaaaaaaabbbbbbccccc", "xc"),
  anythingInCommon("aaaaaaaaaaaaaabbbbbbccccc", "x")
)

anythingInCommon('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','cddabddde')

Fiddler:http://jsfiddle.net/LRxGK/4/

答案 2 :(得分:2)

单程,

实际上扩展了你的地图方法

为您的字符集创建两个bit Arrays,例如a-z创建一个bit array of 26,以及您遇到的任何字符set the flag to 1。 所以你一次读string A个字符lookup in string B's flagArray看看相应的位是否打开,(在字符串A的flagArray中将此位设置为'on'),在同一次迭代中,执行此操作对于字符串B的当前字符和A的标志阵列,如果它们都不匹配,则在两个位阵列中为当前字符设置相关位

答案 3 :(得分:1)

字符串就像数组一样工作,我们想要的是模仿javascript中的set.intersect来获取两个容器的常用字母,因为JS没有本机集,你可以查看这个答案:

Simplest code for array intersection in javascript

添加其他答案,如果字符串已经排序,可以快速快速地执行此操作

  1. 检查每个排序字符串中的第一个字母,如果它们相等。退出truthy

  2. 弹出两个第一个字符中的最小字符

  3. 如果任何字符串为空,则返回false

  4. 转到1。

答案 4 :(得分:1)

构建后缀树或使用动态编程可以解决这个问题 请参阅Longest common substring problem,它可能会有所帮助。

答案 5 :(得分:1)

每个人都会因为使用正则表达式而对我大吼大叫,但这会让生活变得简单

var str1 = 'Stop and stay'
,   str2 = 'JavaScript'.replace(/(.)(?=.*\1)|\s/g, "")
// replace(): removes space & repeated characters

,   reg = new RegExp("["+ str2 +"]", 'g')
// global flag to return a list of matched characters
;

console.log(str1.match(reg));
// array('S', 't', 'a', 'p', 't', 'a')

JSFIDDLE

答案 6 :(得分:1)

这个答案借鉴了gaurav5430和megawac的答案。

此算法构造一个集合,其中包含出现在任一字符串中的每个字符。

  • 以O(n)
  • 运行
  • 不需要对字符串进行排序
  • 它同时检查两个字符串
  • 一旦到达两个字符串中存在任何字符的点,它就会终止,即使该字符是第一个字符。
  • 这是JSFiddle example
function common_char(left, right) {
  var left_map = {};
  var right_map = {};
  var index = 0;

  while (index < left.length || index < right.length) {

    // Check left array
    if (index < left.length) {
      var c = left[index];

      left_map[c] = true;

      // Check if it exists in the other map
      if (right_map[c]) {
        return true;
      }
    }    

    // Check right array
    if (index < right.length) {
      var c = right[index];

      right_map[c] = true;

      // Check if it exists in the other map
      if (left_map[c]) {
        return true;
      }
    }

   index++;
  }

  return false;
}

答案 7 :(得分:0)

如果你在容器中搜索元素可以包含任意值的元素,那么由于容器没有排序,你不可能比执行线性搜索O(N ^ 2)更快地完成这个操作。通过使用两个嵌套的for循环迭代字符串中的元素。正如你无疑注意到的那样,这在JavaScript中会相当慢。

但是,字符通常是有限集的一部分(例如,ASCII的128个字符)。因此,在构建两个映射时可能是值得的,每个映射一个映射,并在您进行搜索时将字符串中的字符插入到相应的映射中。这样,您可以在比较匹配的下一个字符之前检查先前是否在字符串映射中看到过某个字符。根据您的典型字符串长度,这可能比进行简单的线性搜索更快。

如果您要将相同的字符串与其他字符串进行多次比较,那么在搜索之前完全预先排序您的字符串(例如通过使用地图)也可能仍然是一个选项,因为这样排序的初始成本将在后续搜索中摊销

答案 8 :(得分:0)

想出了我自己的解决方案,我的想法是与目前最大的地图进行比较。它类似于古斯塔夫·伯特伦(Gustav Bertram)的方法,但是自适应地选择接下来要比较的字符,字符串A或字符串B.

function haveCommonChar(a, b) {
    var mapa = [], mapb = [], mappeda = 0, mappedb = 0, x = 0, y = 0
    while(x < a.length && y < b.length) { // smart part, while both strings still have more chars
        if (mappeda >= mappedb) { //compare against the largest map
            // one way to speed up this part even further, will be to work in chunks of fixed size larger than 1(now it's 1)
            var c = b.charCodeAt(y++)
            if (mapa[c] === 1) return true
            if (mapb[c] !== 1) mapb[c] = 1, mappedb++
        } else {
            var c = a.charCodeAt(x++)
            if (mapb[c] === 1) return true
            if (mapa[c] !== 1) mapa[c] = 1, mappeda++
        }
    }
    //quickly finish the remaining chars
    while(x < a.length) if (mapb[a.charCodeAt(x++)] !== undefined) return true
    while(y < b.length) if (mapa[b.charCodeAt(y++)] !== undefined) return true
    return false
}