【发布时间】:2020-01-06 04:46:11
【问题描述】:
我写了一个函数,它有 2 个字符串,s 和 a,它应该返回 a 在 s 中第一次出现的位置。它可以将 a 作为一个字符正常工作,但如果第一次出现在 s 中的第三个字符之后,它将停止工作。
我已经检查了 mul 和 add 是否正确,a 的哈希是否正确,并且我已将基数减少到 10 和 100(这对于哈希不是很好,因为它们不是素数)并且它有效(在长度为 20 的字符串)。这可能意味着模数不能按预期工作。
function getIndex(s, a) {
// 2 bases and 2 mods to reduce the number of collisions
var base1 = 31337;
var base2 = 31357;
var mod1 = 1e9 + 7;
var mod2 = 1e9 + 9;
//suffix arrays
var hs1 = new Uint32Array(s.length);
var hs2 = new Uint32Array(s.length);
// bases to the power of a.length
var ba1 = 1;
var ba2 = 1;
// hashes for a
var ha1 = 0;
var ha2 = 0;
//operators
var mul = (x, y, mod) => (x * y) % mod;
var add = (x, y, mod) => {
x += y;
if(x >= mod) x -= mod;
if(x < 0) x += mod;
return x;
}
//get hash of a and find value of ba1 and ba2
for(var i = 0; i < a.length; i++) {
ha1 = add(mul(ha1, base1, mod1), a.charCodeAt(i), mod1);
ha2 = add(mul(ha2, base2, mod2), a.charCodeAt(i), mod2);
ba1 = mul(ba1, base1, mod1);
ba2 = mul(ba2, base2, mod2);
}
//make suffix array
var h1 = 0;
var h2 = 0;
for(var i = 0; i < s.length; i++) {
h1 = add(mul(h1, base1, mod1), s.charCodeAt(i), mod1);
h2 = add(mul(h2, base2, mod2), s.charCodeAt(i), mod2);
hs1[i] = h1;
hs2[i] = h2;
}
//Compare hashes of substrings of s (by removing prefix from the current element) with hash of a
for(var i = a.length - 1; i < s.length; i++) {
var h1 = hs1[i];
var h2 = hs2[i];
if(i >= a.length) {
console.log(i, i - a.length, h1);
h1 = add(h1, -mul(hs1[i - a.length], ba1, mod1), mod1);
h2 = add(h2, -mul(hs2[i - a.length], ba2, mod2), mod2);
}
if(h1 == ha1 && h2 == ha2) return i - a.length + 1;
}
return -1;
}
getIndex("abcdefgh", "f") //returns 5
getIndex("abcdefgh", "fg")//returns -1
【问题讨论】:
-
你能解释一下你的哈希函数的目的是什么吗?它与检索另一个字符串中出现子字符串的第一个索引的任务有什么关系?如您所知,这可以通过
s.indexOf(a)轻松完成。 -
因为在这个例子中, indexOf 的复杂度是 (n - m) * m (或简化的 O(n * m) ),但是使用散列(在这个代码中,它的目的是转换字符串到数字)和后缀数组我认为复杂度将是 O(n)(从 0 到 m 的循环为 1,从 0 到 n 的循环为 2)。
-
我没有解释它的目的是什么,我使用散列创建了一个数字后缀数组,代表字符串的后缀。由于这个散列函数的属性(如果我从后缀数组中取
(x - len)th elem,将它乘以len的幂并从xth 元素中减去,我将从@ 得到子字符串的散列987654327@th 元素到xth 元素)我可以非常快速地获取每个子字符串的哈希值,并将其与我正在寻找的字符串的哈希值进行比较(这是比较数字,也应该很快)。 -
好的,所以你想比较 hashed 字符串。我认为您的函数仍应比较 纯文本 字符串。
-
您的“后缀数组”似乎存储了前缀的哈希值?
标签: javascript string debugging hash