String Compression
Tu reçois une chaîne s composée de lettres anglaises. Compresse-la : remplace chaque suite d’au moins deux lettres identiques consécutives par cette lettre suivie de la longueur de la suite, et laisse telle quelle une lettre qui apparaît seule. Ainsi, aabccc devient a2bc3. Renvoie la chaîne compressée.
Les majuscules et les minuscules sont des lettres différentes : aA correspond à deux suites de longueur 1.
Fonction
- sstring
- la chaîne à compresser, lettres anglaises uniquement
- Renvoiestring
- la chaîne compressée, chaque séquence étant écrite sous la forme de sa lettre suivie de sa longueur lorsque celle-ci est supérieure à 1
Contraintes
1 ≤ s.length ≤ 2 × 104sne contient que des lettres anglaises, deaàzet deAàZ.- Une longueur de séquence est écrite en décimal et peut comporter plusieurs chiffres.
Exemples
- Entrée
- s = "aabccc"
- Sortie
- "a2bc3"
- Explication
- Les séquences sont
aa,betccc. Elles deviennenta2,b(une lettre isolée n’a pas de compteur) etc3.
- Entrée
- s = "abbbbbbbbbbbb"
- Sortie
- "ab12"
- Explication
- Un
a, puis douzeb. La longueur 12 s’écrit avec les deux caractères1et2, donc le résultat estab12.
- Entrée
- s = "zzZZZ"
- Sortie
- "z2Z3"
- Explication
- La lettre minuscule
zet la lettre majusculeZsont différentes, donc il s’agit d’une suite de deux suivie d’une suite de trois :z2Z3.
Pour aller plus loin
Écrivez l’opération inverse : à partir d’une chaîne compressée telle que ab12, reconstruisez l’originale. Comment lire un nombre de répétitions composé de plusieurs chiffres ?
Indices
Ouvrez-les un par un. Chacun en dévoile un peu plus.
Lisez
scomme une rangée de blocs, chaque bloc étant constitué d’une même lettre répétée. De quelles deux informations sur un bloc avez-vous besoin pour l’écrire ?Chaque bloc a besoin de sa lettre et de sa longueur. Garde un index à l’endroit où le bloc commence et avance un second index tant qu’il voit la même lettre ; la distance entre les deux correspond à la longueur.
Gardez
iau début d’une séquence et déplacezjjusqu’à ce ques[j]soit différent ou que la chaîne se termine. Écrivezs[i], puisj-isous forme de texte décimal si sa valeur est supérieure à 1, et déplaceziàj. Une longueur telle que 12 correspond à deux caractères.
Solution
Trouvez où commence et où se termine chaque suite de lettres identiques, puis écrivez sa longueur sous forme de texte. Une suite d’une seule lettre ne reçoit aucun décompte, et un décompte peut comporter plusieurs chiffres. Deux index, l’un au début d’une suite et l’autre qui parcourt celle-ci jusqu’à sa fin, permettent de le faire en un seul passage.
Rassemble les séries, puis écris-les
Intuition
Commence par enregistrer les séquences sous forme de paires composées d’une lettre et d’une longueur : pour aabccc, (a, 2), (b, 1), (c, 3). Chaque lettre prolonge la dernière séquence ou en ouvre une nouvelle. Écris ensuite la lettre de chaque séquence, suivie de sa longueur si elle est supérieure à 1.
Les deux parcours sont en O(n). La liste peut contenir n séquences lorsqu’aucune lettre adjacente ne correspond ; elle nécessite donc un espace supplémentaire de O(n).
Algorithme
- Crée une liste vide de séquences.
- Pour chaque lettre de
s: si la dernière séquence contient la même lettre, ajoute 1 à sa longueur ; sinon, ajoute une nouvelle séquence de longueur 1. - Pour chaque séquence, écris sa lettre, puis sa longueur en notation décimale si elle est supérieure à 1.
def compress(s):
# First pass: collect the runs as [letter, length] pairs
runs = []
for ch in s:
if runs and runs[-1][0] == ch:
runs[-1][1] += 1
else:
runs.append([ch, 1])
# Second pass: write each run, with its length when it is more than 1
parts = []
for letter, length in runs:
parts.append(letter)
if length > 1:
parts.append(str(length))
return "".join(parts)Deux pointeurs sur chaque séquence
Intuition
Garde i à la première lettre du groupe courant et avance j tant que s[j] est égal à s[i]. Lorsque j s’arrête, sur une lettre différente ou à la fin, la longueur du groupe est j-i. Écris-la et définis i = j. Pour abbbbbbbbbbbb, j s’arrête d’abord à 1, ce qui donne a, puis à 13, ce qui donne b12.
Le dernier groupe ne nécessite aucun cas particulier, car la boucle interne s’arrête à la fin de la chaîne. j ne fait qu’avancer, donc le temps d’exécution est O(n), et en plus du résultat, tu conserves deux index. Les versions en R et en Swift divisent d’abord s en un tableau de caractères ; elles utilisent donc un espace supplémentaire de O(n).
Algorithme
- Définissez
i = 0. - Tant que
ise trouve dans la chaîne, définissezj = iet avancezjtant qu’il se trouve dans la chaîne et ques[j]est égal às[i]. - Écrivez
s[i]; sij-iest supérieur à 1, écrivez-le sous forme de texte décimal. - Définissez
i = jet recommencez.
def compress(s):
parts = []
n = len(s)
i = 0
while i < n:
# Move j to the first index after the run that starts at i
j = i
while j < n and s[j] == s[i]:
j += 1
parts.append(s[i])
if j - i > 1:
parts.append(str(j - i))
i = j
return "".join(parts)
Pièges et cas limites
- Écrire une séquence uniquement lorsque tu rencontres une lettre différente. Rien ne suit le dernier
cccdeaabccc, donc tu renvoiesa2b. - Écrire le compte sur un seul caractère, par exemple
'0' + count. Cela échoue à 10 : douzebnécessitent les deux caractères12. - Écrire
1après une lettre isolée.bresteb, et nonb1. - Ignorer la casse.
zzZZZdonnez2Z3, et nonz5. - Faire croître une chaîne immuable avec
+, comme en Java ou en C#. Chaque+copie le résultat obtenu jusque-là, ce qui rend la boucleO(n²); utilise un générateur de chaînes.
Questions fréquentes3
Quelle est la complexité temporelle de la compression de chaînes ?
Le parcours à deux pointeurs prend un temps de O(n), car l’index de parcours ne fait qu’avancer. En dehors du résultat, il conserve deux index, donc l’espace supplémentaire est de O(1).
La chaîne compressée peut-elle être plus longue que l’originale ?
Pas dans cette version. Une lettre isolée reste un caractère, et une suite de k ≥ 2 lettres devient une lettre suivie des chiffres de k, jamais plus de k caractères. Un schéma qui écrit un compte après chaque lettre, comme a1b1, peut doubler la longueur.
Comment compresser une chaîne en place ?
Utilise un tableau de caractères avec un index de lecture et un index d’écriture. Parcours chaque série avec l’index de lecture, puis écris sa lettre et les chiffres de sa longueur à l’index d’écriture. La sortie n’est jamais plus longue que l’entrée lue jusqu’alors, donc l’index d’écriture ne dépasse jamais l’index de lecture. Renvoie la nouvelle longueur à la fin.
Problèmes similaires
Des problèmes qui reposent sur les mêmes idées. En résoudre deux ou trois, c’est ce qui ancre un schéma.
def compress(s):
# Écrivez le code iciTest #1
Test #2
Test #3
Argument
s = "aabccc"
Résultat attendu
"a2bc3"