最快乘法:普通数字a的p次幂怎么求速度最快,不用Math.pow(a,p)哦
提示:重要的优化算法基础知识
一定要熟练掌握这个快速乘幂的方法(a的p次幂),今后咱们要把a换成矩阵,去求矩阵A的p次幂,在那你可以看到速度的优势
题目
普通数字a的p次幂怎么求速度最快,不用Math.pow(a,p)哦
一、审题
示例:10的75次方怎么求?
普通求法:pow(a,p),复杂度o§
//最快乘法:普通数字a的p次幂怎么求速度最快,不用Math.pow(a,p)哦
//如果用pow
public static void test(){
System.out.println(Math.pow(10, 75));
}
public static void main(String[] args) {
test();
}
系统给出来的结果
1.0E75
一般系统幂pow咋做?
循环×75次10呗,好说
还有递归实现
就说循环实现的复杂度吧,o§
你循环×这么多次,就是慢!!!
最快乘法,复杂度o(log§)
咱们这么搞
在计算机中,系统存的p就是一个二进制数
p=75=1001011
75=
10的75次方=
所以咱们拿着p=75这个数的二进制数(系统存的就是二进制呢)
从右往左(从0位开始数x),看有1的地方,×10的位x次幂
循环×就是10的p次幂
看图:
初始化,a=1,t=10的1次方
(1)p的0位x=1:a=a×t=1×10的1次方=10的1次方,t=t×t=10的2次方
(2)p的1位x=1:a=a×t=10的1次方=10的1次方×10的2次方,t=t×t=10的4次方
(3)p的2位x=0:a=a×t=10的1次方=10的1次方×10的2次方 ,t=t×t=10的8次方
(4)p的3位x=1:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方 ,t=t×t=10的16次方
(5)p的4位x=0:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方 ,t=t×t=10的32次方
(6)p的5位x=0:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方 ,t=t×t=10的64次方
(7)p的6位x=1:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方×10的64次方 ,t=t×t=10的128次方
此时a已经是a的p=75次方了
实际上,咱们用了几次算出这个结果了?1–7就6次!!!6=log(p=75)
o(log§) 比 o§ 速度快多了吧!!!
你看懂了上面我怎么做的了吗??
实际上,就是利用二进制,当p的位x是1的地方,把10的k次方×给a
最后就得到了a的p次幂
这是不是很妙?
咱们手撕代码,你看完代码就知道这很妙
//用p的二进制数求a的p次幂
public static double aItsPCiMi(int a, int p){
//a=10,p=75
// p=1001011,二进制数,从右边开始看x位
// 初始化,a=1,t=10的1次方
//(1)p的0位x=1:a=a×t=1×10的1次方=10的1次方,t=t×t=10的2次方
//(2)p的1位x=1:a=a×t=10的1次方=10的1次方×10的2次方,t=t×t=10的4次方
//(3)p的2位x=0:~~a=a×t=10的1次方=10的1次方×10的2次方~~ ,t=t×t=10的8次方
//(4)p的3位x=1:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方 ,t=t×t=10的16次方
//(5)p的4位x=0:~~a=a×t=10的1次方=10的1次方×10的2次方×10的8次方~~ ,t=t×t=10的32次方
//(6)p的5位x=0:~~a=a×t=10的1次方=10的1次方×10的2次方×10的8次方~~ ,t=t×t=10的64次方
//(7)p的6位x=1:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方×10的64次方 ,t=t×t=10的128次方
//此时a已经是a的p=75次方了
double ans = 1;
double tmp = a;//基数a的1次方开始
//看p的右边开始数的位次x的1和0情况来决定
for(; p != 0; p >>= 1){//每次p往右移位1位
if ((p & 1) != 0){
//p的这个位x=1的话
ans *= tmp;
}
//不管p情况如何,tmp照常倍增
tmp *= tmp;
}
return ans;
}
//如果用pow
public static void test(){
int a = 10;
int p = 75;
System.out.println(Math.pow(a, p));
System.out.println(aItsPCiMi(a, p));
}
就用p去控制ans是否倍×tmp,决定在x=1的地方×10的1 2 4 8 16 32 64这种次方,来计算a的p次方
每次tmp都要倍×tmp,保持10的1 2 4 8 16 32 64这种次方往上快速涨
测试结果:
1.0E75
1.0000000000000001E75
够牛吧?
总结
提示:重要经验:
1)求a的p次幂,完全可以利用二进制来优化乘幂,这样的最快乘法的速度可以加速到复杂度o(log§)
2)一定要熟练掌握这个乘幂的方法,今后咱们要把a换成矩阵,去求矩阵A的p次幂,在那你可以看到速度的优势
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。