【问题标题】:How to calculate nth n-digit palindrome efficiently?如何有效地计算第 n 个 n 位回文数?
【发布时间】:2012-08-12 20:59:34
【问题描述】:

我认为这个问题很简单,可以理解。为了更清楚,我举个例子:

在 2 位回文列表中,第 7 个回文是 77(第 1 个是 11,第 2 个是 22,依此类推)。

显然存在蛮力解决方案,但效率不高。

谁能给我一些更好的解决方案来解决这个问题?

【问题讨论】:

  • 第 7 个 4 位回文数应该是 0770 ?
  • 不,回文中不能有前导零。
  • 如果允许前导零,那么 77 将是第八个两位数回文。由于 77 是第七个两位数回文(根据任务描述),不允许使用前导零。
  • 它类似于 number=n+10(^length/2)-1 然后使用 sprintf 或其他东西将其转换为字符串 + 添加反向
  • 只是吹毛求疵:“nth n-digit palindrome”不是您描述的问题...您可能是指“nth m-digit palindrome”:)

标签: c++ c algorithm palindrome


【解决方案1】:

首先,我们可以简化问题,因为我们只需要查看数字的前半部分(如果有奇数位,则四舍五入)。我将把第一组数字称为有效数字,其余的称为非有效数字

这是因为非重要数字必须与重要数字匹配(相反)。不可能有另一个具有相同前导有效数字和不同非有效数字的回文数。 有效数字确定整个回文数。

现在,我们只需要想出一个算法来生成第 n 个有效的有效数字。如果我们允许前导零,这会更容易,所以我们将提出允许前导零的算法,然后调整算法。

前几个回文(有效数字)将是:

  • 1:0000
  • 2:0001
  • 3:0002
  • ...
  • 100:0099

所以我们可以通过求 (n-1) 的十进制表示来找到第 n 个数的有效数字。

为了在不允许前导零时调整算法以使其工作,我们将从一开始作为前导数字:

  • 1:1000
  • 2:1001
  • 3:1002
  • ...
  • 100:1099

这归结为找到 (n-1) + 1000 = n + 999 的十进制表示并展开成一个完整的回文

示例:找出第 113 个长度为 9 的回文。

  • 确定要查看的位数:向上取整(9 / 2) = 5 --> 只查看前 5 位。
  • 查找要添加的数字以消除前导零:10^(5-1) = 10000
  • 使用公式:(113 - 1) + 10000 = 10112
  • 扩展为回文:101121101

顺便说一句,这个算法也可以推广到寻找任何有序符号集(或字母表)的第 n 个回文。

广义算法

给定:找到回文数 n ,回文有 m 个符号作为数字,有 p 个符号(十进制有 10 个符号)

  • q = 上限(m / 2)
  • 偏移量 = p ^ (q - 1)
  • 数字 = (n - 1) + 偏移量
  • answernumber 展开为回文

【讨论】:

    【解决方案2】:

    前几个 7 位回文是:

    • 1000001
    • 1001001
    • 1002001
    • 1003001
    • ...
    • 1009001
    • 1010101
    • 1011101
    • ...

    我觉得从什么是nthm-digit回文数的模式很容易看出...

    【讨论】:

    • 为什么不从 1000,001 开始?
    【解决方案3】:

    当位数为偶数时,只需从100..0开始取第n个位数减半的数,其中长度为位数的一半。回文就是这个数字后跟它的镜像。

    对于奇数位数,只需取该数字一半的上限,然后以相同的方式从 100...0 开始计数。然后回文是这个数字后跟它的镜像,去掉了第一个数字。

    第 65 个 10 位数字:

    65 + 9999 = 10064

    1006446001

    第 10298 个 13 位数字:

    10298 + 999999 = 1010297

    1010297920101

    【讨论】:

      【解决方案4】:

      对于两位数的回文数,两个连续回文数之间的差是 11。

      【讨论】:

        【解决方案5】:

        类似:

        #include<iostream>
        #include<cmath>
        #include<cstring>
        #include<cstdio>
        using namespace std;
        
        void reverseString(char *dest,char *src){
         char *iter=src;
         while (*iter) iter++;
         while (iter!=src){
          iter--;
          *dest=*iter;
           dest++;
         }
         *dest=0;
        }
        
        char *pal(int n,int len){
          char *tmp=new char[len/2+2];
          char *out=new char[len+1];
          sprintf(out,"%i",n+int(pow(10.0,(len+1)/2-1))-1);
          reverseString(tmp,out); //copy reversed out into tmp
          strcat(out,tmp+len%2);
          delete []tmp;
        return out;
        }
        
        int main(){
         cout<<pal(4,7)<<endl;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-12-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-08
          • 1970-01-01
          相关资源
          最近更新 更多