确定一个数字是否是时间O的幂(log log n)

时间:2013-10-26 14:29:13

标签: algorithm math big-o time-complexity

对于作业,我需要找到一种算法,可以测试数字n是时间O(log log n)时间的4的幂。我不知道如何处理这个问题,也不知道哪些数据结构或算法是合适的。有没有人对如何解决这个问题有任何建议?

6 个答案:

答案 0 :(得分:4)

O(log log n)要求有点奇怪。如果你正在处理无界的整数,并且这些整数用通常的二进制形式表示,那么你真的无法检查n的所有位。在这种情况下,你不可能比O(log n)做得更好。另一方面,如果您只计算基本操作,可以在O(1)时间内完成。

这是一些Python代码:

>>> def is_power_of_four(n):
...     return n & (n-1) == 0 and n % 3 == 1
... 
>>> [n for n in range(-10**6, 10**6) if is_power_of_four(n)]
[1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144]

就位操作而言,此算法为O(log n)。就操作计数而言,它是O(1)。说明:n & (n-1)是应用于nn-1的{​​{3}}操作。当且仅当n为2的幂或n == 0时,该值为零。在两个权力中,四个权力的余数13,而其他两个权力的余数2。余数测试也方便地排除案例n == 0

如果您还想知道四个n次幂,而不仅仅是确定n是否为4的幂,那么这是一个不同的问题,templatetypedef已经给出了有效的答案。

答案 1 :(得分:4)

如果你知道单词大小,你可以比O(log log N)做得更好 - 实际上,你可以在O(1)中用它编译下来的4个机器指令。例如,如果假设32位整数,则可以执行以下操作:

int is_power_of_4(int x) {
    return ( (x & (-x)) & 0x55555554 ) == x;
}

对于不同的字大小,只需更改常量。

x & (-x)技巧是一个众所周知的黑客,它返回的数字只是x中最不重要的1位。 & 0x5554然后屏蔽两个奇数幂,然后比较原始失败,如果x中有任何其他设置位。

答案 2 :(得分:2)

我将假设数字表示为固定宽度的整数,它允许在时间O(1)内完成基本操作,如比较,加法,乘法等。

请注意,如果您有一个数字n,则该数字n中包含O(log n)位。如果我们让b是数字中的位数,那么期望的运行时间将是O(log b)。换句话说,我们希望找到一些函数,其运行时间是数字中位数的对数。

由于我们试图检查数字是否为4的幂,我们试图查看该数字是否具有某个数字k的形式4 k 。这是我们可以用来做到这一点的一种可能方法:

  1. 计算4 1 ,4 2 ,4 4 ,4 8 ,4 16 ,...,4 2 x 直到我们找到一个大于数字n的数字。这意味着如果n是4的幂,则它必须是夹在4 0 和4 2 x 之间的4的幂。由于以下原因,此步骤最终将采用O(log log n)时间:数字n可写为4 log 4 n 。一旦4 2 x ≥4 log 4 n ,上述过程就会终止 x ≥log 4 n,当x≥log 2 log 4 n时发生。因此,只有O(log log n)总迭代次数,每次迭代需要时间O(1)。

  2. 在[0,2 x ]范围内进行二元搜索,以确定k的哪个值(如果有)满足n = 4 k 。此步骤的运行时间为O(x),因为在大小为2 x 的范围内,二进制搜索将花费时间O(log 2 x )= O(x) 。而且,我们知道x = O(log n)。在步骤(1)中,我们保持指数加倍,直到它超过log 4 n的值。这意味着在最坏的情况下,x可以是2 log 4 x,因此x = O(log n)。因此,此步骤也需要O(log log n)时间。

  3. 由于步骤(1)和(2)各自花费时间O(log log n),因此总体时间复杂度为O(log log n)。

    注意:您可以将此问题视为n的对数上的“猜数字游戏”的变体。一个经典的采访问题是“我正在考虑一个自然数n,你应该试着猜测它。”您可以使用上述方法在O(log n)时间内解决它。在这种情况下,您试图猜测4的指数是否正常,因此您可以将该过程应用于数字的对数以获得O的运行时间(log log n)。

    希望这有帮助!

答案 3 :(得分:0)

对于无符号整数,您可以使用:

bool is_pow4(DWORD x)
    {
/*
    4^0 =    1 = 00000000001b
    4^1 =    4 = 00000000100b
    4^2 =   16 = 00000010000b
    4^3 =   64 = 00001000000b
    4^4 =  256 = 00100000000b
    4^5 = 1024 = 10000000000b
    -------------------------
    or together  10101010101b
    negate       01010101010b = A....AAAh

*/
    if (!x) return false;
    if (DWORD(x&(x-1))) return false;   // not power of 2 (more than 1 bit is set)
    return !(x&0xAAAAAAAA);             // not setted any bit from negated mask
    }
  • 它与Lee Daniel Crocker的答案基本相似
  • 但它只使用无符号的整数
  • 并且还检测到1为4的幂,这是真的(Lee Daniel Crocker代码错误)
  • 还添加了一些内容以更好地理解它是如何工作的
  • 主要思想是pow2检测
  • pow2号码只有1位和0(二进制)
  • 所以pow2 -1只是一个(二进制)
  • 如果你和它在一起应该得到0
  • 假设它也是4的力量只是使用否定的面具
  • 如果位设置在错误的位置(pow2而不是pow4)而不是简单并检测它
  • 可以使用任何位数...掩码总是AAAAAAA .... AAAAAh为4的权力

这里也解决了非常类似的问题:https://stackoverflow.com/a/19888301/2521214

PS。复杂性与x - ,&

  • 所以对于正常数字O(1)
  • 和bignums取决于实施通常为O(log n)
  • 以bignum为基础记录,例如log(2 ^ 32,n)

答案 4 :(得分:0)

使用面膜稍微便宜一些。

#include <stdio.h> 
#include <string.h>

int main ()
{
   int x;
   int mask;

   memset(&mask, 0x55, sizeof(int));
   scanf("%d",&x);

   if ((x) && ((x & (x-1)) == 0) && (x & mask))
       printf("Power of four\n");
   else
       printf("Not power of four\n");
   return (0);
}

答案 5 :(得分:0)

在此提供机器便携式解决方案。此解决方案不需要任何预先计算的数字,也不会对机器的位宽做出任何假设。

bool isPowerOfFour(int num) {
    int s = ceil(sqrt(num));
    // s > 0 makes sure 0 is not power of four
    // 4^x -> 2^(2x) so sqrt of it should be 2^x all we need to do is to tell whether the sqrt is a power or two
    // but firstly we need to make sure sqrt(num) is an integer so we use s*s == num
    // then use (s&(s-1)) == 0 to tell whether it is a power of 2
    return s > 0 && s*s == num && (s&(s-1)) == 0; 
}