【leetcode】2961. 双模幂运算

77 阅读2分钟

leetcode-2961.png

按照题目的意思做就好了,但是。。。不能ac,而且刚开始写的代码不够优雅

var getGoodIndices = function (variables, target) {
    let res = []
    for (let i = 0; i < variables.length; ++i) {
        let tmp = (variables[i][0] ** variables[i][1] % 10) ** variables[i][2] % variables[i][3]
        if (tmp === target) {
            res.push(i)
        }
    }
    return res
};

这上面要用解构来做,就好看很多。但是呢,这么做又不能ac。主要是因为时间复杂度太高了 理解下面的算法,主要是理解modExp函数。
如果我们想求得 x的64次幂,那么就 x * x * x ... * x = x^64
但是还有一种办法就是
x * x = x2x^{2}
x2x^{2} * x2x^{2} = x4x^{4}
x4x^{4} * x4x^{4} = x8x^{8}
x8x^{8} * x8x^{8} = x16x^{16}
x16x^{16} * x16x^{16} = x32x^{32}
x32x^{32} * x32x^{32} = x64x^{64}
这样子就是经过6次计算即可

但是我们计算的过程中,是很少会遇见 2n2^{n} 这种"整数"幂
那我们就要处理下这种非2n2^{n}的幂了

比如说给定一个x 的 23次幂,也就是 x23x^{23}
result = 1, base = x
首先,是一个奇数,我们就可以得到
result = result * base = x
base = x * x = x2x^{2}
exp = 23 / 2 = 11 (向下取整

result = x * base = x3x^{3}
base = x2x^{2} * x2x^{2} = x4x^{4}
exp = 11 / 2 = 5

result = x3x^{3} * base = x7x^{7}
base = x4x^{4} * x4x^{4} = x8x^{8}
exp = 5 / 2 = 2

exp == 偶数
base = x8x^{8} * x8x^{8} = x16x^{16}
exp = 2 / 2 = 1

exp == 奇数
result = x7x^{7} * base = x23x^{23}
base = x8x^{8} * x8x^{8} = x16x^{16}
exp = 1 / 2 = 0


22 次幂
base = x * x = x2x^{2}
exp = 22 / 2 = 11 (向下取整

result = 1 * base = x2x^{2}
base = x2x^{2} * x2x^{2} = x4x^{4}
exp = 11 / 2 = 5

result = x2x^{2} * base = x6x^{6}
base = x4x^{4} * x4x^{4} = x8x^{8}
exp = 5 / 2 = 2

exp == 偶数
base = x8x^{8} * x8x^{8} = x16x^{16}
exp = 2 / 2 = 1

exp == 奇数
result = x6x^{6} * base = x22x^{22}
base = x8x^{8} * x8x^{8} = x16x^{16}
exp = 1 / 2 = 0

经过上面的计算过程,我们可以得知,每次我们都将 base进行自乘,遇到奇数幂,就单独再乘以一个 x 即可

var getGoodIndices = function (variables, target) {
    let res = [];
    for (let i = 0; i < variables.length; ++i) {
        let [a, b, c, m] = variables[i];

        let tmp = modExp(modExp(a, b, 10), c, m)
        if (tmp === target) {
            res.push(i);
        }
    }
    return res;
};

var modExp = function (base, exp, mod) {
    let result = 1
    while (exp > 0) {
        base %= mod
        // 遇到奇数幂,就再单独成
        if (exp % 2 === 1) {
            result = (result * base) % mod
        }
        base = (base ** 2) % mod
        exp = Math.floor(exp / 2)
    }
    return result
}