我需要在C中编写一个递归函数,对于某个n,它会计算不具有三个连续数字1的n位二进制数的数量。
例如,对于n = 3,所有可能的3位数都是: 000 001 010 011 100 101 110 111
所以函数返回7,因为只有一个数字有三个1。
到目前为止,我甚至不知道从哪里开始。我无法看到任何可以帮助我的算法。
任何帮助将不胜感激。 感谢。
答案 0 :(得分:3)
让我们构建一个从左到右没有三个连续的数字。
它必须以最多两个1开始,因此它从无1,单个1或两个1开始。换句话说,我们的数字从0,10或110开始。在所有这些情况下,对数字的其余部分的唯一限制是它不包含任何三个连续的,所以这允许我们应用相同的函数递归:
#include <stdint.h>
#include <stddef.h>
uint64_t nothreeconsecutive(int n) {
if (n <= 2) return 1 << n;
return nothreeconsecutive(n-1) + nothreeconsecutive(n-2) + nothreeconsecutive(n-3);
}
答案 1 :(得分:1)
首先观察 don t 包含三个相邻设置位的n位二进制数的数量是pow(2, n)
减去n的数量位号与三个相邻的设置位。
此外,设置了三个相邻位的长度n
的二进制数的数量是长度n-1
的数量的两倍(最后一位的两个值都导致具有三个相邻位的数字) set),加上设置了初始两位的长度为n-1
的二进制数的数量(对于设置新位的情况),减去长度n-1
的数量和设置的两个初始位之前已经设置了三个相邻位(因为它们已被计数一次)。
因此,在更改返回类型以使计算更长的序列后,问题的解决方案可能如下所示:
#include <stdint.h>
#include <stddef.h>
uint64_t twoadjstart(int a)
{
/*returns the number of binary numbers with a bits that have no more than 2 adjacent initial set bits.*/
if (a < 2)
return 0;
if (a == 2)
return 1;
return UINT64_C(1) << (a - 3);
}
uint64_t recuadjthree(int a)
{
/*returns the number of binary numbers with a bits that do contain three adjacent set bits.*/
if (a < 3)
return 0;
uint64_t retval = 2*recuadjthree(a-1);
retval += twoadjstart(a-1);
retval -= recuadjthree(a-4);
return retval;
}
uint64_t recunothree(int a)
{
/*returns the number of binary numbers with a bits that do not contain three adjacent set bits.*/
uint64_t combi = UINT64_C(1) << a;
return combi - recuadjthree(a);
}
答案 2 :(得分:0)
将数字视为位串,因此问题在于如何找到子串111
。关于位的好处是你可以对其进行位移,并尝试屏蔽低三位,并比较它是否为111
。试试这个:
bool valid(int n) {
while (n) {
if ((n & 0x7) == 7)
return false;
n = n >> 1;
}
return true;
}
其次,考虑如何获得所有n位数。您可以很容易地注意到这些数字来自所有0到0的所有数字,因此您可以循环遍历所有这些数字,并在第一步中使用该函数检查每个数字。 / p>
现在你有了一个迭代解决方案,想一想如何实现与递归相同的东西。
答案 3 :(得分:-1)
以下是错误的(部分)解决方案(由@EOF指出)。
我将离开错误的解决方案,因此评论将有意义,并且寻找正确解决方案的人可以从错误中吸取教训。
错误:此解决方案仅涉及n
位数,最后3位设置为1
,忽略了1
的可能性位将位于数字的中间。
可能:完成此解决方案需要我们一次又一次地将n-1
(直到n == 0)的解决方案从解决方案中减去n
。< / p>
#include <stdio.h>
#define pow2(n) ipow(2,n);
int solution(int n)
{
if(n <= 2)
return pow2(n);
return pow2(n) - pow2(n-3);
// The return statement, after the `if`, should probably have been:
return pow2(n) - pow2(n-3) - solution(n-1);
}
int main()
{
int n = 7;
printf("The solution for n = %d is %d", n, solution(n));
}
我的逻辑:
如果有n
位,那么可能的数字(包括0)的数量是2 ^ n(n的幂为2)。
在n位数中,有n-2种方式来拟合三个连续的设置位(0b111
,0b1110
,0b11100
)...这是IF n&gt; 2。
正如评论中所指出的,这些数字中的每一个都有非0位可能性(即0b11101
以及0b11100
)。
所以:
对于n = 3,我们剩下0位(1个可能的数字== 2 ^ 0)
对于n = 4,我们剩下1位(2个可能的数字== 2 ^ 1)
对于n = 5,我们有2个剩余的位,分开或一起(4个可能的解决方案== 2 ^ 2)。
等...
这些可能性是剩余比特(n-3)的幂的2。
...我怀疑比特的位置是重要的,我们知道我们对所有可能的数字都有2 ^ n个排列,如果三个比特相同,那么我们有2 ^(n-3)个排列数字。
感谢KlasLindbäck和EOF的指示。