给定范围[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)
数字。
注意:这是一个面试问题。面试官对上述方法不满意。
我们可以做得更好吗?
答案 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的幂,则将其拆分为两个范围,
q
和第一部分到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;