使用非线性时间复杂度算法求解x的N次幂
最简单的想法是采用N-1个乘法循环来实现。但当幂级很高时,对计算机来说将是一个灾难,因此本文参考了相关书目之后,给出低于线性时间的算法。
参考书目:数据结构与算法分析(C语言描述)Mark Allen Weiss著。
递归算法
典型的减小时间复杂度的做法是记住程序已经做的事情,避免在做重复的事情,比如使用N-1个循环乘法就是一直在做重复的乘x。通过记住x,x2,x4,…,等数据,可以大大减小时间的复杂度。程序如下:
//包含头文件
#include <iostream>
#include <vector>
using namespace std;
double pow(int x, unsigned int n) {
if(n==0)
return 1;
if(n==1)
return x;
if(!(n%2))//判断是否是偶数
return pow(x*x,n/2);//偶数递归方法
else
return pow(x*x,n/2)*x;//奇数递归方法
}
按照递归程序运行,时间复杂度为O(log2N)。
非递归算法
在幂上做加法,相当于同底相乘,比如:
x2+2=x2*x2=x4
因此还有一个办法就是直接将幂转换为二进制数,从最后一位开始,依次代表x1, x2, x4, , ,xm的系数。若某位为0,则幂的分解中没有该位代表的幂。例如:
3=2+1,3的二进制表示为11,即,
x3=x2*x1,因此,使用数组c存储x,x2, x4, , ,然后根据二进制选择位上为1对应的数组c的项进行相乘即可。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int powers(int x, int N) {
if (0==N)
return 1;
int poly=1;
vector<int> c;
vector<int> d;
dToB(N, d);//将幂次转为二进制
reverse(d.begin(), d.end());//将容器的内容从begin到end进行翻转
for (int i = 0; i < d.size(); ++i) {
c.push_back(x);//根据d的位数进行存储
x=x*x;
}
for (int i=0;i<d.size();++i) {
if (d[i]!=0)//选择二进制不为0的项相乘
poly *=c[i];
}
return poly;
}
//转为二进制的程序
bool dToB(int &x, vector<int> &bb) {
if (x < 0)
return false;
else {
while (x>=2) {
bb.push_back(x % 2);//对x取余
x=x/2;//将x除以2并赋值
}
bb.push_back(x);
reverse(bb.begin(), bb.end());//顺序需要换一下
return true;
}
}
按照非递归的方法,时间复杂度为O(log2N)。
欢迎批评指正。