在logn时间和恒定空间中计算功率函数

时间:2014-10-01 20:52:59

标签: algorithm math pow

我在接受采访时遇到的这个问题。 假设我想计算功率(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)时间和恒定空间的界限?

3 个答案:

答案 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;
}

注意上面的内容可以通过大多数语言中的位操作和/或掩码进行优化,但是我不确定你正在编写哪种语言,所以我试图使它成为非委托/易读的,让你根据需要修改/优化它。