在计算a^n次方时,先将n变一变,寻找新的计算路径,预处理就是变治法的根本!算法
若是单纯循环执行n次相乘,那么时间复杂度为O(n),n为指数;利用二进制幂大大改进效率。数组
利用二进制幂求解分两种方法:从左至右二进制幂 和 从右至左二进制幂。spa
变换:
code
a^n = a^(b[n]2^n + ... + b[0]2^0) == ((b[n]*2 + b[n-1])*X + ....)2 + b[0]input
先求n的二进制串:it
如 5 -> 1 0 1, 那么b[2] = 1, b[1] =0, b[0] =1io
Horner(b[0...n], x)
k = b[n]
for i = n-1 downto 0 do
p = x*k + b[i]
return pclass
那么n用做a的指数时意义是什么样的呢:效率
a^p = a^1
for i = n - 1 downto 0 do
a^p = a^(2p+b[i])
循环
n变换方法:
a^n = a^(b[n]2^n + ... + b[0]2^0) == ((b[n]*2 + b[n-1])*X + ....)2 + b[0]
而后从b[0] -> b[n]方向逐步求解
详细代码:
#include <stdio.h> #include <stdlib.h> /* * 返回number二进制串 */ int GetBinArray(int number, int arr[], int size) { int idx = 0; while (number > 0) { if (number & 1) arr[idx++] = 1; else arr[idx++] = 0; if (idx == size) break; number = number >> 1; } return idx; } /* * a^n = a^(b[n]2^n + ... + b[0]2^0) = a^(b[n]2^n) * ... * a^b[0] * b数组元素不是1就是0 */ int Pow_Bin_RightToLeft(int number, int p) { if (p == 0) return 1; int size = sizeof(int)*8; int *pint = (int *)malloc(size); int length = GetBinArray(p, pint, size); int idx; int item = number; int ret = 1; for (idx = 0; idx < length; idx++) { if (pint[idx] == 1) ret = ret * item; item *= item; } free(pint); return ret; } /* * a^n = a^(b[n]2^n + ... + b[0]2^0) == ((b[n]*2 + b[n-1])*X + ....)2 + b[0] * b数组元素不是1就是0 */ int Pow_Bin_LeftToRight(int number, int p) { if (p == 0) return 1; int size = sizeof(int)*8; int *pint = (int *)malloc(size); int length = GetBinArray(p, pint, size); int ret = number; int idx; for (idx = length-1-1; idx >= 0; --idx) { ret *= ret; if(pint[idx] == 1) ret *= number; } free(pint); return ret; } int main(int argc, char *argv[]) { printf("Please input number and pow:\n"); int number,p; scanf("%d%d", &number, &p); int ret = Pow_Bin_RightToLeft(number, p); int ret1 = Pow_Bin_LeftToRight(number, p); printf("Pow_Bin_RightToLeft: %d^%d == %d\n", number, p, ret); printf("Pow_Bin_LeftToRight: %d^%d == %d\n", number, p, ret1); main(0, NULL); return 0; }两个算法时间复杂度均为logn.