j’implémente directement une solution en base B quelconque (2≤B≤36). Dans la suite du texte je note Δ le plus grand chiffre de cette base (9 en base 10, F en base 16, 1 en base 2, …).
L’idée de base commence par éliminer deux cas particuliers :
Après ce filtre, on se retrouve donc avec un nombre d’au moins deux chiffres dont le palindrome suivant possédera le même nombre de chiffres.
Par exemple :
808 → plus grand palindrome interne 808 → ajout de 1 à partir du milieu → 818
898 → plus grand palindrome interne 898 → ajout de 1 à partir du milieu → 908 → copie miroir → 909
3221 → plus grand palindrome interne 3221 → copie miroir hors palindrome interne → 3223
12328 → plus grand palindrome interne 12328, chiffre à gauche plus petit que celui à droite → copie miroir → 12321 → ajout de 1 à partir du milieu 12421 → copie miroir → 12421
3284 → plus grand palindrome interne 3284 → chiffre à plus petit que celui à doite → copie miroir → 3223 → ajout de 1 à partir du milieu → 3323 → copie miroir → 3333
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static uint8_t values[] = {
['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4, ['5'] = 5,
['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9, ['a'] = 10, ['b'] = 11,
['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15, ['g'] = 16, ['h'] = 17,
['i'] = 18, ['j'] = 19, ['k'] = 20, ['l'] = 21, ['m'] = 22, ['n'] = 23,
['o'] = 24, ['p'] = 25, ['q'] = 26, ['r'] = 27, ['s'] = 28, ['t'] = 29,
['u'] = 30, ['v'] = 31, ['w'] = 32, ['x'] = 33, ['y'] = 34, ['z'] = 35,
['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15,
['G'] = 16, ['H'] = 17, ['I'] = 18, ['J'] = 19, ['K'] = 20, ['L'] = 21,
['M'] = 22, ['N'] = 23, ['O'] = 24, ['P'] = 25, ['Q'] = 26, ['R'] = 27,
['S'] = 28, ['T'] = 29, ['U'] = 30, ['V'] = 31, ['W'] = 32, ['X'] = 33,
['Y'] = 34, ['Z'] = 35,
};
static bool valid[] = {
['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true,
['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true,
['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true,
['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true,
['z'] = true, ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true,
['E'] = true, ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true,
['J'] = true, ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true,
['O'] = true, ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true,
['T'] = true, ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true,
['Y'] = true, ['Z'] = true,
};
typedef struct {
char *input;
int base;
bool done;
size_t number_len;
uint8_t *number;
size_t nextpal_len;
uint8_t *nextpal;
} input_data_t;
input_data_t get_data(const char *input, int base);
void compute_nexpal(input_data_t *data);
void display(input_data_t data);
int main(int argc, char *argv[]) {
input_data_t data = get_data(argv[1], argv[2] ? atoi(argv[2]) : 10);
compute_nexpal(&data);
display(data);
}
input_data_t get_data(const char *input, int base) {
if (base < 2 || base > 36) {
fprintf(stderr, "base invalide\n");
exit(EXIT_FAILURE);
}
input_data_t data;
data.input = strdup(input);
data.base = base;
data.number_len = strlen(input);
if (data.number_len < 1) {
fprintf(stderr, "nombre invalide\n");
exit(EXIT_FAILURE);
}
data.number = malloc(data.number_len * sizeof *data.number);
bool all_last_digit = true;
for (size_t i = 0; i < data.number_len; i++) {
if (!valid[(int)input[i]]) {
fprintf(stderr, "caractère invalide\n");
exit(EXIT_FAILURE);
}
uint8_t value = values[(int)input[i]];
if (value != base - 1)
all_last_digit = false;
if (value >= base) {
fprintf(stderr, "chiffre invalide\n");
exit(EXIT_FAILURE);
}
data.number[i] = value;
}
if (all_last_digit) {
data.done = true;
data.nextpal_len = data.number_len + 1;
data.nextpal = calloc(data.nextpal_len, sizeof *data.nextpal);
data.nextpal[0] = data.nextpal[data.nextpal_len - 1] = 1;
} else if (data.number_len == 1) {
data.done = true;
data.nextpal_len = data.number_len;
data.nextpal = calloc(data.nextpal_len, sizeof *data.nextpal);
data.nextpal[0] = values[(int)input[0]] + 1;
} else {
data.done = false;
data.nextpal_len = data.number_len;
data.nextpal = calloc(data.nextpal_len, sizeof *data.nextpal);
memcpy(data.nextpal, data.number, data.number_len);
}
return data;
}
void compute_nexpal(input_data_t *data) {
if (data->done)
return;
ssize_t middle = data->nextpal_len / 2;
ssize_t left = middle - 1;
ssize_t right = middle + (data->nextpal_len % 2);
bool left_smaller = false;
while (left >= 0 && data->nextpal[left] == data->nextpal[right]) {
left--;
right++;
}
left_smaller = (left < 0 || data->nextpal[left] < data->nextpal[right]);
while (left >= 0) {
data->nextpal[right] = data->nextpal[left];
right++;
left--;
}
if (left_smaller) {
int carry = 1;
left = middle - 1;
if (data->nextpal_len % 2) {
data->nextpal[middle] += carry;
carry = data->nextpal[middle] / data->base;
data->nextpal[middle] %= data->base;
right = middle + 1;
} else {
right = middle;
}
while (left >= 0) {
data->nextpal[left] += carry;
carry = data->nextpal[left] / data->base;
data->nextpal[left] %= data->base;
data->nextpal[right++] = data->nextpal[left--];
}
}
data->done = true;
}
void display(input_data_t data) {
printf("le palindrome suivant %s en base %d est : ", data.input, data.base);
for (size_t i = 0; i < data.nextpal_len; i++)
putchar(digits[data.nextpal[i]]);
putchar('\n');
}
Le code mériterait largement une simplification. J’ai pris le parti de ne saisir que des chaînes que je transforme en tableau d’entiers pour les manipulations.
Du coup en base 36, nextpal(256344510514743751332437247280545791⏨,36)=256344510514743751399753977111200702⏨