如何生成仅包含2种数字的第n个数字?

时间:2015-09-20 13:29:51

标签: algorithm c++11

我们将特殊号码定义为仅包含4和7的数字。

让我们看看示例:447477444777特殊数字,而407 ISN'吨

我需要帮助才能了解生成Nth特殊号码的法律/规则是什么。

我尝试了下面的代码,但它没有工作

int x[2000];
int k=0;

void dfs( int a ) {
  if(k==1021)
    return;
  x[k++]=a;
  dfs(a*10+4);
  dfs(a*10+7);
}

dfs(4);
dfs(7);

关于如何做的任何解决方案或想法?

4 个答案:

答案 0 :(得分:4)

为此,我们可以使用二进制。将4s称为0,将7s称为1,因为7> 4。假设我们正在寻找第n个特殊号码。将k定义为具有第n个特殊数字的较少位数的特殊数字的数量。现在,我们看到如何使用二进制文件。假设我们知道第10个特殊数字有3位数,那个k = 6。我们正在寻找3位特殊数字列表中的10-6 =第4个数字。

4 - 0 77 - 11

7 - 1 444 - 000

44 - 00 447 - 001

47 - 01 474 - 010

74 - 10 477 - 011< -Here

如图所示将它们映射到二进制,问题变得更容易。 m位特殊数字的数量将是2 ^ m,并且记住两个的前m个幂的总和是2 ^(m + 1)-1。如果我们有一个3位数字,那么我们通过将1位和2位数字相加得到k,留下我们的2 ^ 0 + 2 ^ 1 + 2 ^ 2 = 2 ^ 3-1。排除0位数字,我们将2 ^ 3-2作为k,这推广到2 ^位-2。为了找到位数,我们需要找出两个低于n的幂。这只是log2(n),但是我们必须将它排成一行并得到一个整数,所以我们采用下限(log2(n + 1))。从这里开始,我们只使用n-k-1的二进制表示,然后使用按位函数提取每个数字并将数字添加到我们的答案中。

int nthspecialnum( int n )
{
    int digits = (int)(log2(n+1));
    int k = pow( 2, digits ) - 2;
    int binary = n - k - 1;
    int answer = 0;
    for( int i = 0; i < digits; i++ ) {
        bool is7 = ((binary >> i) % 2) == 1;
        answer += (is7 ? 7 : 4)*pow( 10, i );
    }
    return answer;
}

这些数字变得非常快,所以如果你正在寻找大n并且不想要出现负数,你可以简单地将数字保存在数组中而不是整数并打印出来顺序出来。

答案 1 :(得分:1)

明显的答案:测试7和4:

bool check (unsigned int number) {
    if(number == 0)
        return false;
    while(number != 0) {
        unsigned int digit = number % 10;
        if( digit != 4 && digit != 7 )
            return false;
        number /= 10; // integer division, ie. "rounding down"
    }
    return true;
}

int main(int argc, char **argv) {
    for(int number = 0; number <= 100; number ++) {
        if(check(number)) 
             do_what_ever_you_want(number);
    }
    return 0;
}

答案 2 :(得分:1)

为什么代码被破坏

您的代码无法正常工作,因为您的终止条件取决于在第二次调用k之前未重置的全局变量dfs(7)。因此,此调用终止而不生成任何新的特殊号码。所以最后你会错过以7开头的所有特殊号码。

您可以通过调用:dfs(0)并丢弃x数组的第一个条目来解决此问题。但是整个程序编写得很糟糕。依赖函数内部的全局变量是对灾难的呼唤。

生成所有特殊数字的算法

如果数字在0到100之间,那么它有0,1或2位数字。

基本上所有特殊数字都是:4,7,44,47,74,77。

如果要扩展到d个数字,则可以使用二进制数d位。选择值为0的位为小数位4,值为1的位将转换为十进制数字7。然后,通过枚举02^d-1之间的所有值,您可以生成所有特殊数字。

在前一种情况下,我们列举了所有特殊数字:

  • 1位,转换为2个特殊数字:4 ad 7
  • 2位,转换为4个特殊数字:44477477

如何获取第N个特殊号码 首先,我们考虑基于1的索引。

您只需要注意二进制表示少于d位的特殊数字的计数是:2^1+2^2+...+ 2^d = 2(2^d-1) = 2^(d+1)-2

您可以执行一个简单的循环递增d,直到2^(d+1)-2不严格低于n。这告诉您应该为d使用n位二进制表示。您将2^d-2减去n并减去1,因为我们使用基于1的索引。最终的数字现在可以通过上述步骤生成一个特殊数字。

示例:第5个特殊号码

2^2-2 = 2 <  5   => d+1 > 2
2^3-2 = 6 >= 5   => d+1 = 3  => d = 2

n-2^d+2-1 = 5-4+2-1 = 2 = 10b (using 2 bits as d = 2)

=> 5th special number is: 74

答案 3 :(得分:1)

我试着按照你的想法回答这个问题。 也许有人会从中得到帮助。

int x[2000];
int k = 0;
const int num_len = 8;

void dfs(int a, int level)
{
    if (level > num_len)
        return;
    x[k++] = a;
    dfs(a * 10 + 4, level + 1);
    dfs(a * 10 + 7, level + 1);
}

int main()
{
    memset(x, 0, sizeof(x));
    dfs(0, 0);
    sort(x, x+k);

    int nth;
    cin >> nth;
    cout << x[nth] << endl;
    return 0;
}