数字的最小基数,使其在该基数中表示为回文

时间:2014-08-03 11:16:17

标签: c math data-structures

给定一个整数x,我必须找到最小基数 b(b> 1),以便x 基础 b是回文。

例如:5个碱基2是回文序列,即5个碱基2:101是回文序列。除了解决暴力问题之外,如何以更好的方式解决它?

3 个答案:

答案 0 :(得分:4)

公平警告:这不是一个完整的答案,而是一些可能有用的注释。希望到目前为止,问题和评论具有非正统性,没有人会对此感到不安。 :)

  • 基地2
    • 11:3
    • 101:5(+2)d
    • 111:7(+2)2
    • 1001:9(+2)d
    • 1111:15(+6)2
    • 10001:17(+2)d
    • 10101:21(+4)
    • 11011:27(+6)2
    • 11111:31(+4)
    • 100001:33(+2)d
    • 101101:45(+12)
    • 110011:51(+6)2
    • 111111:63(+12)
  • 基地3
    • 11:4
    • 22:8(+4)1
    • 101:10(+2)d
    • 111:13(+3)
    • 121:16(+3)
    • 202:20(+4)1
    • 212:23(+3)
    • 222:26(+3)
    • 1001:28(+2)d
    • 1111:40(+12)
    • 1221:52(+12)
    • 2002:56(+4)1
    • 2112:68(+12)
    • 2222:80(+12)
  • 基地4
    • 11:5
    • 22:10(+5)1
    • 33:15(+5)1
    • 101:17(+2)d
    • 111:21(+4)
    • 121:25(+4)
    • 131:29(+4)
    • 202:34(+5)1
    • 212:38(+4)
    • 222:42(+4)
    • 232:46(+4)
    • 303:51(+5)1
    • 313:55(+4)
    • 323:59(+4)
    • 333:63(+4)

我将之前的差异标记为(+ n),最后添加了一些注释:

  • 1:此处增加的第一个数字
  • 2:这里增加了第二个数字(我只为基数2标记了这个数字;在其他地方似乎无关紧要)
  • d:此处递增的位数(并且第一位数字重置为1)

一些结构性观察:

  • 基地中的第一个(最小的)回文总是(基数+ 1)。我们不允许1,也不允许任何前导零。
  • (N <碱)的前N个回文是N *(碱+ 1)。
  • (基础)回文总是比(基数-1)多2(并且总是表示为101)。
  • 2位数的回文数是(基数-1)。
  • 3位和4位回文数是(基数-1)*碱。

最后,一些欠发达的想法:

  • x的回文表示的位数是1 + log_base(x)。
  • 给定长度的第一个回文总是10..01。
  • 当最后没有标记时(即第一个数字和数字位数都不变),您可以看到重复差异的模式。这可能让我们快进#34;通过从10..01开始的候选回文。

答案 1 :(得分:4)

这必须以粗暴的方式解决,但你可以通过在你的方法中应用一些逻辑来避免使它成为一种蛮力搜索,从而消除一些候选人。

例如,您可以避免测试数字可被整除的碱基,从而节省碱基转换过程以及回文测试。原因很简单:在任何基数中的表示可能不以零开头,这意味着数字也不会以该表示中的零结束,否则不会是回文。

在基础 x 表示中以零结尾的数字表示该数字可以用 x 整除,而不会有余数。

此提示不能转移到其他数字,因为休息可以是在该基础中可表示的任何内容。

不幸的是,我无法提出任何其他通用逻辑来消除候选人。但是,我可以想出另一个会降低基数的上限以检查候选者,之后可以肯定地说答案只是基础(x - 1) x

x 的基础(x - 1)产生11作为表示,这是一个回文。随着基数减少,表示中的数字变得更大,或者我们得到更多的数字。

  • 基座2中的下一个最小的回文将是101
  • 任何大于2的基数中的下一个最小的回文将是22

让我们从反向检查,从顶部开始:

for (int base = x - 1; base >= 2; base--)
    // is x represented palindromic at base (base)

想象一下这对于一个大的 x 。答案最初将是,然后我们将在很长一段时间内开始。这是为什么?让我演示一下:

/*
base    representation
x - 1   11
x - 2   12
x - 3   13
x - 4   14
...
x - n   1n
...
x-x/2   20 or 21    for x even or odd
x / 2   20 or 21    for x even or odd

直到 x / 2 ,第二个数字(从最后一个)将保持不变,第一个数字将逐个缓慢增加。

x / 2 x / 3 之间类似,但这两者之间的差异更小(x / 6与x / 2相比) ,以及第一个数字将开始逐两增加;因此,将这种逻辑应用于其余部分变得越来越不重要。

好的,出于这个原因,除了小于6的数字之外,如果我们碰巧找不到任何小于(x / 2)的基数,那么对于数字 x 的回文表示,我们可以安全地放弃并说答案是(x - 1)

所有这些文字,只解释了两个可以实施的简单逻辑,以防止多余的测试:

  • 不检查数字<= li>的正确除数的基数
  • 如果检查超过(x / 2)(x - 1)的快捷方式 x 大于或等于6

最后一次讨论:如果主题在不同的基础上表示,为什么受到任何字母表中字母的限制?特别是当我们在电脑上工作时?只需使用整数数组,每个元素用数字正确表示数字,而不是任何字母或其他任何东西。就像字符串一样,可以使用终止值,可以是-1。计算机可能要容易得多,因为无论如何它都不会来回转换成字母。

这是一个源代码,它完成了我上面解释的内容:

#include <stdio.h>
#include <malloc.h>

int ispalindrome(const int * string)
{
    int length = 0;
    while (string[length] != -1)
        length++;

    for (int i = 0; i < length / 2; i++)
    {
        if (string[i] != string[length - 1 - i])
            return 0;
    }
    return 1;
}

int * converttobase(int number, int base)
{
    int length = 0;
    int temp = number;
    while (temp)
    {
        length++;
        temp /= base;
    }
    int * result = calloc(length + 1, sizeof * result);

    for (int i = length - 1; i >= 0; i--)
    {
        result[i] = number % base;
        number /= base;
    }
    result[length] = -1;

    return result;
}

int lowestpalindromebase(int number)
{
    int limit = (number < 6) ? (number + 2) : (number / 2);
    // if number is more than or equal to 6, limit candidates with the half of it
    // because, reasons...

    for (int base = 2; base < limit; base++)
    {
        if (number % base)  // number does have a remainder after division with base
        {
            int * converted = converttobase(number, base);
            if (ispalindrome(converted))
            {
                free(converted);
                return base;
            }
            free(converted);
        }
    }

    return number - 1;
}

int main( )
{
    for (int i = 1; i < 60; i++)
    {
        printf("%2d is palindromic at base %d\n", i, lowestpalindromebase(i));
    }

    return 0;
}

答案 2 :(得分:1)

对于后人来说,这是一种蛮力的方法,检查从3到1000.你只是&#39;必须检查从2n-1的基数,因为基数n中的n-1始终是11 - 它可能是11的最小基数。仍然是回文。

奇怪的是,只有数字3,4,6,11和19需要一直检查n^2 + 1。 最多1000个,有60个二进制回文,所以这些都是在第一次尝试时找到的。

正如可以预料的那样,在基数36之上,它无法找到许多数字的回文。

两个三个值得注意的重复值:

  • 基础n中的任何数字101均为n^2
  • 基础n-1中的任何数字121均为1[0*]1
  • x^n+1的所有搜索结果似乎都是int is_palindrome (char *string) { int l = strlen(string), l2 = (l+1)>>1, i = 0; while (i < l2) { if (string[i] != string[l-1-i]) return 0; i++; } return 1; } int main (void) { char buf[256]; int number, base, check; int per_base[36] = { 0 }; for (number=3; number<=1000; number++) { check = 0; for (base=2; base<=min(36,number-1); base++) { itoa (number, buf, base); if (is_palindrome (buf)) { check++; per_base[base]++; printf ("%d in base %d is %s\n", number, base, buf); break; } } if (!check) printf ("%d is not a palindrome in anything up to 36\n", number); } for (number=2; number<36; number++) printf ("%d-ary palindromes: %d\n", number, per_base[number]); return 0; }
{{1}}