使用位运算来判断两个字符串是否有相同字符

295 阅读1分钟

这个题目是由Leetcode的最大长度单词乘积衍生而来。

问题: 如何判断两个字符串是否有相同的字符?

示例:

"abcw", "fxyz" => false // 两个字符串没有相同字符

"a","aa" => "a" // 相同字符"a"

"abc","bdcde" => "bc" // 相同字符"bc"

分析:

最先想到的是什么呢?选择最短的字符串进行遍历,将每一个字符串和另一个的字符串进行比较来判断是否含有相等字符串。

function hasSameCode(strA, strB) {

  let maxLenStr, minLenStr

  if (strA.length > strB.length) [maxLenStr, minLenStr] = [strA, strB]
  else[maxLenStr, minLenStr] = [strB, strA]

  for (let i of minLenStr) {
    if (maxLenStr.includes(i)) {
      return true
    }
  }

  return false
}

通过两个循环for of includes 来直接遍历判断是否含有相同字符,时间复杂度最坏的情况是O(m * n),那么换一种思路呢?

位运算

可以使用位运算预处理每个单词,通过位运算操作判断两个单词是否有公共字母。由于单词只包含小写字母,共有 26 个小写字母,因此可以使用位掩码的最低 26 位分别表示每个字母是否在这个单词中出现。将 a 到 z 分别记为第 0 个字母到第 25 个字母,则位掩码的从低到高的第 i 位是 1 当且仅当第 i 个字母在这个单词中,其中0 ≤ i ≤ 250。

function hasSameCode2(strA, strB) {

  let codeA = 0
  for (let i of strA) {
    codeA |= 1 << (i.charCodeAt() - "a".charCodeAt())
  }

  let codeB = 0
  for (let i of strB) {
    codeB |= 1 << (i.charCodeAt() - "a".charCodeAt())
  }

  return (codeA & codeB) !== 0
}