判断一个字符串是否为另一个字符串的子串,是则返回所在索引,不是返回-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
}