下面的代码均为 C++ 代码!
1. 普通快速幂
-
- 解法:递归或者迭代(时间复杂度均为\(O(log\space n)\),递归空间复杂度为 \(O(log\space n)\),迭代空间复杂度为 \(O(1)\) );
-
迭代算法详解:(参考了官方题解:Pow(x, n) - 方法二:快速幂+迭代)
我们的目标是求 \(x\) 的 \(n\) 次方。任何一个整数都可以用2的幂次方的和表示,这里就不证明了(学计算机的应该不至于这点都不会),因此可以使用二进制表示/存储(说白了就是数的二进制),例如5的二进制是101。即任意一个整数 \(n\),有
\[n=a_02^0+a_12^1+...+a_k2^k \\ \]其中 \(a\) 为系数,取值为 0或1。
因此,
\[\begin{align} x^n &= x^{(a_02^0+a_12^1+...+a_k2^k)} \\ &=x^{a_02^0}·x^{a_12^1}· \space ... \space ·x^{a_k2^k} \end{align} \]由于,
\[\begin{align} x^{2^{(b+1)}}&=x^{(2^{b}·2^1)}=x^{(2·2^b)}=x^{(2^b+2^b)}=x^{2^b}·x^{2^b} \space \\ 即,\quad x^{2^{(b+1)}}&=x^{2^b}·x^{2^b}=[x^{2^b}]^2 \end{align} \]因此,可以从 \(x\)(即 \(x^{2^0}\))开始平方得到 \(x^{2^1}\),\(x^{2^1}\)再平方得到 \(x^{2^2}\),...,直到得到 \(x^{2^k}\) 。在平方的过程中我们只需要在n的相应的二进制位为1时将相应的累平方乘以前面的结果就可(例如 n 的 第c位 为1,则将 \(x^{2^c}\) 乘以 answer 就可,answer是快速幂的结果,详细看下面的代码),直至遍历完 \(n\) 的所有位!
class Solution { double quickMul(double x, long long n) { double answer = 1.0; double squareX = x; // x,即为x^(2^0) while (n > 0) { if (n % 2 != 0) { // 最后一位为1,则说明该 answer *= squareX; } squareX *= squareX; // 累平方 n >>= 1; // n右移一位,也可以将n除以2 } return answer; } public: // 求x的n次方 double myPow(double x, int n) { return n > 0 ? quickMul(x, n) : 1.0 / quickMul(x, -(long long)n); } };
2. 矩阵快速幂(了解)
-
下面为求裴波那契数列的第n项的代码(详细看上面的链接):
// 定义一个 Solution 类封装需要的函数 class Solution { const int MOD = 1000000007; // 2*2矩阵(方阵)乘法 vector<vector<long long>> matrixMul(vector<vector<long long>> &x, vector<vector<long long>> &y) { vector<vector<long long>> res(2, vector<long long>(2)); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { res[i][j] = (x[i][0] * y[0][j] + x[i][1] * y[1][j]) % MOD; } } return res; } // 矩阵快速幂 vector<vector<long long>> fastExponentiation(vector<vector<long long>> &x, int n) { vector<vector<long long>> res = {{1, 0}, {0, 1}}; // 单位矩阵 vector<vector<long long>> exponent = x; // 2^0 while (n) { if (n & 1) { res = matrixMul(res, exponent); } exponent = matrixMul(exponent, exponent); n >>= 1; } return res; } public: int fib(int n) { vector<vector<long long>> x = {{1, 1}, {1, 0}}; // 定义矩阵M return n < 2 ? n : fastExponentiation(x, n - 1)[0][0]; } };