Lorsqu'on travaillle sur une chaîne de caractères A de taille n, composée exclusivement de chiffres et de lettres alphabétiques, il devient nécessaire d'identifier efficacement la sous-séquence la plus longue formant un palindrome. Cette tâche requiert une approche structurée pour minimiser les temps de calcul.
Approche par Expansion Centrale
Cette méthode consiste à parcourir l'ensemble des indices du vecteur de caractères. Pour chaque position traitée, on considère deux scénarios possibles pour le centre du palindrome : soit un seul indice central (cas des palindromes de longueur impaire), soit un intervalle entre deux indices adjacents (cas des palindromes de longueur paire). On élargit ensuite la zone vers la gauche et la droite tant que les caractères correspondent.
La complexité temporelle résultante est quadratique O(n²), tandis que l'espace mémoire utilisé reste constant O(1).
class SolutionPalindrom {
public:
std::string obtenirLePlusGrand(std::string const& texte) {
int taille = texto.size();
if (taille <= 0) return "";
int debutIndex = 0;
int longueurMax = 0;
for (int k = 0; k < taille; ++k) {
int lenImpair = etendre(texte, k, k);
int lenPair = etendre(texte, k, k + 1);
int currentMax = (lenImpair > lenPair) ? lenImpair : lenPair;
if (currentMax > longueurMax) {
longueurMax = currentMax;
debutIndex = k - (currentMax - 1) / 2;
}
}
return testo.substr(debutIndex, longueurMax);
}
private:
// Fonction auxiliaire pour calculer la longueur du palindrome autour d'un centre
int etendre(std::string const& s, int gauch, int droit) {
while (gauch >= 0 && droit < s.size() && s[gauch] == s[droit]) {
--gauch;
++droit;
}
return droit - gauch - 1;
}
};
Méthode par Programmation Dynamique
Pour cette stratégie, on utilise une matrice bidimensionnelle permettant de stocker l'état logique concernant l'appartenance au palindrome de chaque segment possible défini par ses bornes. La relation de récurrence repose sur la comparaison des extrémités et sur l'état du sous-segment intérieur correspondant.
Formule de transition : table[i][j] est vrai si s[i] == s[j] ET table[i+1][j-1] est vrai.
Ce processus nécessite un ordre d'itération spécifique, généralement en augmentant la longueur du sous-sement, garantissant ainsi la disponibilité des informations nécessaires. La complexité est O(n²) pour le temps et O(n²) pour l'espace.
class SolutionMemo {
public:
std::string chercherPalindromeLong(std::string const& chain) {
int n = chain.length();
if (n == 0) return "";
int longMax = 1;
int posDebut = 0;
// Initialisation de la matrice de vérité
std::vector<:vector>> memo(n, std::vector<bool>(n, false));
// Cas de base : substrings de longueur 1 (toujours vrais)
for(int x = 0; x < n; ++x) {
memo[x][x] = true;
}
// Itération selon la longueur du substring
for (int len = 2; len <= n; ++len) {
for (int i = 0; i <= n - len; ++i) {
int j = i + len - 1;
if (chain[i] == chain[j]) {
if (len == 2) {
memo[i][j] = true;
} else {
memo[i][j] = memo[i + 1][j - 1];
}
}
if (memo[i][j] && len > longMax) {
longMax = len;
posDebut = i;
}
}
}
return chain.substr(posDebut, longMax);
}
};</bool></:vector>
Optimisation Avancée
Il existe des techniques supérieures visant à améliorer la performance globale. En particulier, l'algorithme de Manacher permet de transformer le problème en une opération de complexité linéaire O(n). L'idée fondamentale réside dans la mémorisation intelligente des zones déjà traitées lors de la phase de diffusion centrale, évitant ainsi les recalculs inutiles sur des segments identiques.