【问题标题】:Calculating power function in logn time and constant space在 logn 时间和常数空间中计算幂函数
【发布时间】:2014-11-26 19:55:33
【问题描述】:

我在接受采访时遇到的这个问题。 假设我想计算 x^n 的 power(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) 时间和常数空间的限制?

【问题讨论】:

标签: algorithm math pow


【解决方案1】:

反复进行

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

没有考虑过边缘情况,但我认为它不会太难管理。

【讨论】:

    【解决方案2】:

    如果您尝试了解递归函数如何计算此处的幂,则可以通过迭代方式解决此问题。一种简单的方法是可视化参数如何从基本步骤变化到递归的第一个假设步骤。 [自下而上的观察]

    从基本步骤到第一个假设步骤的递归中的一些观察:

    • 您在每个步骤中将到目前为止找到的答案平方,并且
    • 当每个递归步骤中的指数为奇数时,必须在乘法中包含一个额外的“基数”。这意味着您需要查看指数的二进制表示,并且无论何时设置该位,您都需要将目前找到的答案乘以一个基数。
    • 与递归函数一样,递归状态使用具有一半指数的状态的结果。即您需要在迭代方法中从给定指数的二进制表示的低位到高位

      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 位数

    【讨论】:

      【解决方案3】:

      下面只是分解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;
      }
      

      请注意,以上内容可以在大多数语言中使用位操作和/或掩码进行优化,但我不确定您使用的是哪种语言,因此我尝试使其不明确/易于阅读,以让您根据需要对其进行修改/优化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多