1.1.18

1.1.18 #

解答 #

其实就是一种快速乘法的实现,换成乘号之后就变成了快速乘幂。

例如对于乘法 $2 \times 4$ ,可以用 $2 + 2 + 2 + 2$ 做四次加法计算;也可以变为 $(2 + 2) \times 2 = (2 + 2) + (2 + 2)$ 的形式,用两次加法就可以完成(先计算 $2 + 2$ 的值,再计算 $4 + 4$ 的值)。

同理对于乘幂 $2^8$ ,既可以用 $2\times 2 \times 2 \times 2 \times 2 \times 2 \times 2 \times 2$ 做 8 次乘法,也可以只用三次乘法就计算出来:

$$ 2^2 = 2 \times 2 \newline 2^4 = 2^2 \times 2^2\newline 2^8 = 2^4 \times 2^4 $$

这样时间复杂度就从 $O(n)$ 变为了 $O(log n)$ 。

代码 #

using System;

Console.WriteLine($"Mystery(2, 25): {Mystery(2, 25)}");
Console.WriteLine($"Mystery(3, 11): {Mystery(3, 11)}");

Console.WriteLine($"mysteryChanged(2, 8): {MysteryChanged(2, 8)}");
Console.WriteLine($"mysteryChanged(3, 2): {MysteryChanged(3, 2)}");

// Mystery(a, b) = a * b
// 利用等式:a * b = 2a * b/2 = (2a * (b-1) / 2) + a
// 示例:
// Mystery(2, 25) =
// Mystery(2 + 2, 12) + 2 =
// Mystery(4 + 4, 6) + 2 =
// Mystery(8 + 8, 3) =
// Mystery(16 + 16, 1) + 16 + 2 =
// Mystery(32 + 32, 0) + 32 + 16 + 2 =
// 0 + 32 + 16 + 2 =
// 50
static int Mystery(int a, int b)
{
    if (b == 0)
        return 0;
    if (b % 2 == 0)
        return Mystery(a + a, b / 2);
    return Mystery(a + a, b / 2) + a;
}

// mysteryChanged(a, b) = a ^ b
// 同理(乘方与乘法,乘法与加法之间具有类似的性质)
// a ^ b = (a ^ 2) ^ (b / 2) = (a ^ 2) ^ ((b - 1) / 2) * a
static int MysteryChanged(int a, int b)
{
    if (b == 0)
        return 1;
    if (b % 2 == 0)
        return MysteryChanged(a * a, b / 2);
    return MysteryChanged(a * a, b / 2) * a;
}