Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Minimum base of a number which makes it a palindrome when represented in that base

Given an Integer x, I have to find a minimum baseb(b > 1) such that x base b is a palindrome.

Eg: 5 base 2 is a palindrome i.e. 5 in base 2 : 101 is a palindrome. How to solve it in a better way other than solving it brute-force?

like image 353
CRM Avatar asked Aug 03 '14 11:08

CRM


2 Answers

Fair warning: this is not a complete answer, but some notes which may be useful. Hopefully given the unorthodox nature of the question and comments so far, no one will be too upset by this. :)

  • Base 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)
  • Base 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)
  • Base 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)

I marked the difference from previous as (+n) and on the end added some notes:

  • 1: the first digit incremented here
  • 2: the second digit incremented here (I only marked this for base 2; it seemed irrelevant elsewhere)
  • d: the number of digits incremented here (and the first digit reset to 1)

Some structural observations:

  • The first (smallest) palindrome in a base is always (base+1). We don't allow 1, nor any leading zeros.
  • The first N palindromes for (N < base) are N*(base+1).
  • The (base)th palindrome is always 2 more than (base-1)th (and is always represented as 101).
  • The number of 2-digit palindromes is (base-1).
  • The number of 3- and 4-digit palindromes is (base-1)*base.

And finally, some less-developed ideas:

  • The number of digits of the palindrome representation of x is 1+log_base(x).
  • The first palindrome of a given length is always 10..01.
  • You can see patterns of repeating differences when there is no marker on the end (i.e. when the first digit and the count of digits are both unchanged). This may let us "fast forward" through the candidate palindromes starting from 10..01.
like image 147
John Zwinck Avatar answered Oct 31 '22 18:10

John Zwinck


This has to be solved in a brute manner, but you can avoid making it a brute-force search by applying some logic to your approach, eliminating some of the candidates.

For example, you can avoid testing for bases which the number is divisible with, thus save a base conversion process as well as a palindrome test. The reason is simple: Representation in any base may not start with a zero, and this means that a number may not end with a zero in that representation as well, otherwise would not be a palindrome.

A number ending with a zero in a base x representation means that that number is divisible with x without a remainder.

This hint cannot be carried over to other digits, because rest could be anything that is representable in that base.

Unfortunately, I cannot come up with any other generalized logic to eliminate candidates. I can, however, come up with another one that will bring down the upper bound for bases to check for candidates, after which it can be surely said that the answer is simply base (x - 1) for that x.

Base (x - 1) for x produces 11 as the representation, which is a palindrome. As the bases decrease, either the digits in the representation become larger, or we get more digits.

  • The next-smallest palindrome in base 2 would be 101
  • The next-smallest palindrome in any base greater than 2 would be 22

Let's do the checking from reverse, start from top:

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

Imagine this for a large x. The answer will be yes initially, then we will start having a no for a long while for sure. Why is that? Let me demonstrate:

/*
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

Until x / 2, the second digit (from last) will stay the same and the first one will increase slowly one by one.

It is similar for between x / 2 and x / 3, but the difference in between those two is way smaller (x / 6 compared to x / 2), as well as the first digit will start increasing two by two; therefore applying this logic to the rest becomes less and less significant.

Okay, for this reason, with the exception of numbers that are less than 6, if we happen to fail to find any base less than (x / 2) that yields a palindromic representation for a number x, we can safely give up and say that the answer is (x - 1).

All this text, explaining only two simple logics that can be implemented to prevent superfluous testing:

  • Do not check for bases that are proper divisors of the number
  • Short-cut to (x - 1) if checks exceed (x / 2) for numbers x greater than or equal to 6

One last discussion: If the subject is representation in different bases, why get limited by the letters in any alphabet? Especially when we're working on computers? Just use integer arrays, each element representing a digit properly with numbers and not with any letter or anything else. Just like in strings, a terminating value can be used and that could be -1. Probably a lot easier for a computer, since it won't have to convert things back and forth into letters anyway.

And here's a source code that does what I've explained above:

#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;
}
like image 27
Utkan Gezer Avatar answered Oct 31 '22 16:10

Utkan Gezer