5.字符串匹配算法

147 阅读1分钟

判断一个字符串是否为另一个字符串的子串,是则返回所在索引,不是返回-1

1.BF算法

BF算法即Brute Force,暴力算法,时间复杂度O(n*m)

function f(str,subStr){
  let len1 = str.length 
  let len2 = subStr.length 
  if(len2 > len1) return -1
  
  for(let n = 0; n <= len1-len2; n++){
    // if(str.substring(n,n+len2)==subStr) return n
    
    for(let m = n; m < n+len2; m++){ // 逐位比较
      if(str[m] !== subStr[m-n]) break
      if(m = n+len2-1) return n
    }
    
  }
  return -1
}

2.RK算法

将字符串转为hashcode,迭代将每个字符串转化为哈希值后再作比较操作,为了优化时间复杂度,通常会在迭代过程中采用增量式计算以减少重复计算工作

function f(str,subStr){
  let len1 = str.length
  let len2 = subStr.length
  if(len2 > len1) return -1
  
  let hash = getHash(str.substring(0,j)) // 转哈希
  let subHash = getHash(subStr)
  
  for(let n = 0; n<= len1-len2; n++){
    if(hash==subHash && str.substring(n,n+len2)==subStr) return n
    hash = hash - str.charCodeAt(n) + str.charCodeAt(n+len2) // 增量式,避免再次迭代子串作重复工作
  }
  return -1
}

function getHash(str){
  let hash = 0
  str.forEach(s => hash += s.charCodeAt(0)-96) // a的charCode == 97
  return hash
}


3.KMP算法

生成模式串的前后缀匹配表,从而控制迭代步进,前后缀匹配表由字符串前缀后缀最大共有子串的长度组成

// 生成前后缀匹配表
function getNext(str) {
  let next = [0]
  let j = 0 // 前缀末、最大前缀长
  for (let i = 1, len = str.length; i < len; i++) { // 后缀末
    while (j > 0 && str[j] != str[i]) j = next[j - 1]
    next[i] = str[j] == str[i] ? ++j : j
  }
  return next
}


function kmp(str, subStr) {
  let next = getNext(subStr) 
  let j = 0
  for (let i = 0; i < str.length; i++) {
    while (j > 0 && str[i] != subStr[j]) j = next[j - 1]
    if (str[i] == subStr[j]) j++
    if (j == subStr.length) return i - j + 1
  }
  return -1
}

参考

1. 漫画:什么是字符串匹配算法?