C'est un classique de la programmation dynamique problème (et pas généralement résolu en utilisant des expressions régulières).
Mon implémentation naïve (le comte le 3 pour chaque 2 après chaque 1) a été en cours d'exécution pendant une heure et il n'est pas fait.
Que serait une recherche exhaustive approche qui s'exécute en temps exponentiel. (Je suis surpris qu'il fonctionne pendant des heures tout de même).
Voici une suggestion pour une programmation dynamique de la solution:
Les grandes lignes d'une solution récursive:
(Mes excuses pour la longue description, mais chaque étape est très simple, si patient avec moi ;-)
Si le sous-suite est vide, une correspondance est trouvée (pas de chiffres à gauche de match!) et nous retourner 1
Si la séquence d'entrée est vide, nous avons épuisé nos chiffres et ne peut pas trouver un match donc nous renvoyer 0
(Ni la séquence, ni la sous-suite sont vides.)
(À supposer que "abcdef" désigne la séquence d'entrée, et "xyz": désigne le sous-suite.)
Ensemble result
0
Ajouter à la result
le nombre de matchs pour bcdef et xyz (c'est à dire, jeter la première entrée de chiffres et de recurse)
-
Si les deux premiers chiffres correspondent, c'est à dire, un = x
- Ajouter à la
result
le nombre de matchs pour bcdef et yz (c'est à dire, correspond à la première sous-suite de chiffres et de manière récursive sur les autres sous-suite de chiffres)
De retour result
Exemple
Voici une illustration des appels récursifs pour l'entrée 1221 / 12. (Sous-suite en caractères gras, · représente une chaîne vide.)
La programmation dynamique
Si la mise en œuvre naïvement, certains sous-problèmes sont résolus à plusieurs reprises (· / 2 par exemple, dans l'illustration ci-dessus). La programmation dynamique permet d'éviter une telle calculs redondants, en se rappelant les résultats de déjà résolu sous-problèmes (généralement dans une table de recherche).
Dans ce cas particulier, nous avons mis en place une table avec
- [longueur de la séquence + 1] lignes, et
- [longueur de la sous-suite + 1] colonnes:
L'idée est que nous devons remplir le nombre de matchs pour 221 / 2 correspondant à la ligne / colonne. Une fois cela fait, nous devrions avoir la solution finale dans la cellule 1221 / 12.
Nous avons commencer à peupler la table avec ce que nous savons immédiatement (la "base de cas"):
- Lorsque aucune sous-suite de chiffres à gauche, nous avons 1 correspondance complète:
Ensuite, nous passons par le remplissage de la table de haut en bas / de gauche à droite selon la règle suivante:
-
Dans la cellule [row][col] écrire la valeur trouvée à [ligne-1][col].
Intuitivement, cela signifie "Le nombre de matchs pour 221 / 2 comprend tous les matches pour 21 / 2."
-
Si une séquence à la ligne ligne et subseq au niveau de la colonne col de commencer avec le même chiffre, ajouter de la valeur trouvée à [ligne-1][col-1] à la valeur juste écrit à [row][col].
Intuitivement, cela signifie "Le nombre de matchs pour 1221 / 12 comprend également tous les matchs de 221 / 12."
Le résultat final se présente comme suit:
et la valeur en bas à droite de la cellule est en effet 2.
Dans Le Code
Pas en Python, (toutes mes excuses).
class SubseqCounter {
String seq, subseq;
int[][] tbl;
public SubseqCounter(String seq, String subseq) {
this.seq = seq;
this.subseq = subseq;
}
public int countMatches() {
tbl = new int[seq.length() + 1][subseq.length() + 1];
for (int row = 0; row < tbl.length; row++)
for (int col = 0; col < tbl[row].length; col++)
tbl[row][col] = countMatchesFor(row, col);
return tbl[seq.length()][subseq.length()];
}
private int countMatchesFor(int seqDigitsLeft, int subseqDigitsLeft) {
if (subseqDigitsLeft == 0)
return 1;
if (seqDigitsLeft == 0)
return 0;
char currSeqDigit = seq.charAt(seq.length()-seqDigitsLeft);
char currSubseqDigit = subseq.charAt(subseq.length()-subseqDigitsLeft);
int result = 0;
if (currSeqDigit == currSubseqDigit)
result += tbl[seqDigitsLeft - 1][subseqDigitsLeft - 1];
result += tbl[seqDigitsLeft - 1][subseqDigitsLeft];
return result;
}
}
La complexité
Un bonus pour cette "fill-in-the-table" approche, c'est qu'il est aisé de comprendre la complexité. Une constante de la quantité de travail est effectué pour chaque cellule, et nous avons de la longueur de la séquence de lignes et de la longueur de la sous-suite des colonnes. La complexité est donc en O(MN) où M et N désignent la longueur des séquences.