递归C函数

时间:2016-04-21 13:31:34

标签: c algorithm recursion

我需要在C中编写一个递归函数,对于某个n,它会计算不具有三个连续数字1的n位二进制数的数量。

例如,对于n = 3,所有可能的3位数都是: 000 001 010 011 100 101 110 111

所以函数返回7,因为只有一个数字有三个1。

到目前为止,我甚至不知道从哪里开始。我无法看到任何可以帮助我的算法。

任何帮助将不胜感激。 感谢。

4 个答案:

答案 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种方式来拟合三个连续的设置位(0b1110b11100b11100)...这是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的指示。