我在接受采访时遇到的这个问题。 假设我想计算功率(x,n),即x ^ n。
我所知道的最好的算法是在O(logn)时间内计算pow(x,n),但这是一个递归算法,需要O(logn)空间(调用堆栈)。
int pow(int x, int n)
{
if(n==0)
return 1;
int tmp = pow(x,n/2);
if(n%2)
return tmp*tmp*x;
return tmp*tmp;
}
上述算法在O(logn)时间内运行,但其调用堆栈占用O(logn)空间。 如何在保持O(logn)时间的同时使空间保持不变。
我现在可以想到的算法需要O((logn)^ 2)时间但是在恒定空间中(转换上述算法迭代并以2 ^ i计算pow)。 我们能否达到O(logn)时间和恒定空间的界限?
答案 0 :(得分:0)
迭代地进行
int pow(int x, int n) {
int res = 1;
int mask, topbit;
for (topbit = 0x1, mask = 0x1; n & mask != n; topbit <<= 1, mask = (mask << 1) + 1) {
if (n & topbit)
res *= res * x;
else
res *= res;
}
return res;
}
没有考虑边缘情况,但我认为管理起来太难了。
答案 1 :(得分:0)
如果您试图了解递归函数如何计算此处的功率,则可以以迭代方式解决此问题。一种简单的方法是可视化参数如何从递归的基本步骤变为第一个假设步骤。 [自下而上观察]
从基步到第一个假设步骤递归的一些观察结果:
与递归函数一样,递归状态使用指数一半的状态结果。即你需要在迭代方法中从给定指数的二进制表示的较低位到较高位。
long long int pow(int base, int expt){
// storing the binary representation of "exponent" in stack
stack<int> stk;
while(expt){
stk.push(expt & 1);
expt >>= 1;
}
long long int ans = 1;
while(stk.size()){ // going from lower bit to higher bit
ans *= ans; // squaring step
if(stk.top() == 1){
ans *= base;
stk.pop();
}
return ans;
}
您也可以利用其他一些方法来存储指数位,以使其更容易理解。这里的时间复杂度是 log(n)和恒定的空间复杂度,因为在最坏的情况下,堆栈大小可能是2位数。
答案 2 :(得分:-1)
以下仅分解n
的二进制扩展以执行您的请求。
int pow(int x, int n)
{
int out = 1;
int x_power = 1;
while (n > 0)
{
x_power *= x;
int exponent_bit = n % 2; // Where n % 2 is the least significant bit of n.
n = n / 2; // Assuming your language has n/2 = floor(n/2)
if(exponent_bit == 1) {
out *= x_power;
}
}
return out;
}
注意上面的内容可以通过大多数语言中的位操作和/或掩码进行优化,但是我不确定你正在编写哪种语言,所以我试图使它成为非委托/易读的,让你根据需要修改/优化它。