为什么使用散列搜索字符串的此功能不起作用?

时间:2019-09-03 09:36:24

标签: javascript string debugging hash

我写了一个给定2个字符串s和a的函数,该函数应该返回s中第一次出现的位置。可以将a作为一个字符正常工作,否则,如果第一次出现在s中的第三个字符之后,它将停止工作。

我已经检查了mul并添加了工作,如果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

1 个答案:

答案 0 :(得分:1)

有了更多的日志记录,很显然您是floating point inaccuracies的受害者。 JS数字只能精确表示52位整数。

getIndex("abcdefgh", "fg")中,搜索的哈希值ha13196477,基乘数ba1982007569,在第六次迭代中,前缀哈希为{ {1}}和hs1[6] = 73644174。如果将它们放在算术函数中,则结果为hs1[4] = 800389532,减6。这是因为3196441maximum safe integer大大约两个数量级,并且在JS中,它的计算结果为800389532 * 982007569,这显然是错误的。

您需要选择模数和底数较小,或使用bigints进行所有计算。

相关问题