计算数字,使得一个数字必须将其设定位数作为斐波纳契数?

时间:2017-07-17 16:10:52

标签: algorithm bit-manipulation fibonacci

给定范围[x,y]找到数字的数量,使得一个数字必须将其设定位数作为斐波纳契数?

例如:[15,17]

15 - 1111  - Count of bits is 4 - (4 is not a fibonacci  number)

16 - 10000 - Count of bits is 1 - (1 is a fibonacci number)

17 - 10001 - Count of bits is 2 - (2 is a fibonacci number)

答案是2 (16,17)

显然我们计算设定位,并使用fibonacci是否为完美正方形条件检查其是(5x^2 +/- 4)数字。

注意:这是一个面试问题。面试官对上述方法不满意。

我们可以做得更好吗?

1 个答案:

答案 0 :(得分:5)

你可以对每个斐波那契数字进行反转并计数(达到极限,我会达到这个数字),它产生多少数字"在范围内。

假设k是一个斐波那契数(显然你只会尝试使用斐波那契数,这是很容易产生的)。有多少个数字有k位设置并且在x和y之间?请拨打此countBetween(x, y, k)。只计算一个上限更简单,所以定义countBetween(x, y, k) = countUpTo(y, k) - countUpTo(x, k)(假设你可以轻易改变的独占上限)。

countUpTo(x, k)是2的幂时,{p> x很简单,即log(x) nCr k。如果x不是2的幂,则将其拆分为两个范围,

  1. 两个小于x,q
  2. 的最高功率
  3. 其余的x。
  4. 第一部分到q你已经可以计算,第二部分有一个前导1,然后是一个新的范围(在删除1之后)为0,所以你可以计算countUpTo(x - q, k - 1)

    这为您提供了countUpTo的递归定义,并假设您可以在a nCr b时间内实现O(a nCr b),此算法并不等同于查看每个数字并进行测试。< / p>

    至于限制,显然你不能设置比上限长度更多的位,所以你可以在那里停止。

    示例:countBetween(1024, 1000000, 5) = 15251

    我们需要countUpTo(1024, 5)countUpTo(1000000, 5)countUpTo(1024, 5)是基本情况,结果是log(1024)nCr 5 = 252。

    对于countUpTo(1000000, 5),用十六进制写1000000以便更容易看到正在发生的事情:0xF4240,其中2的最大功率当然是0x80000,贡献log(0x80000)nCr 5 = 11628,将零件从0x80000保留到0xF4240。该部分可以用countUpTo(0x74240‬, 4)计算 - 高位始终设置在该范围内,因此通过调整设置位的界限和数量将其从问题中删除。

    0x74240中2的最大功率是0x40000,贡献为log(0x40000)nCr 4 = 3060,留下countUpTo(0x34240‬, 3)

    0x34240中2的最大功率是0x20000,贡献为log(0x20000)nCr 3 = 680,留下countUpTo(0x14240‬, 2)

    0x14240中2的最大功率是0x10000,贡献为log(0x10000)nCr 2 = 120,离开countUpTo(0x4240‬, 1)

    0x4240中2的最大功率是0x4000,贡献为log(0x4000)nCr 1 = 14.这使countUpTo(0x240‬, 0)为1,因为没有要设置的位,只有一种方式没有设置位。

    将它们全部加起来,11628 + 3060 + 680 + 120 + 14 + 1 = 15503.从下限减去252,得到15251.

    该示例使用相当小的数字,因此您可以通过强力轻松验证它们,例如:

    int count = 0;
    for (int i = 1024; i < 1000000; i++)
        if (__popcnt(i) == 5) count++;
    std::cout << count << std::endl;