Fácil-medio · cadenas

Compresión por longitud

Recorre la línea con un único puntero: el carácter sobre el que estás, cuenta cuántas veces se repite, escríbelo con su contador y ya has pasado el tramo entero. Sin bucles anidados sobre la cadena — el contador ES el bucle interno.

En una fraseAvanza con un índice: en cada posición cuenta el tramo de caracteres iguales, escribe el carácter y el contador (siempre, también 1 — a10 es legal), y continúa tras el tramo.

El problema

Entrada: Una línea de 1 a 200 letras minúsculas, sin espacios.

Salida: La codificación por longitud: para cada tramo maximal, el carácter seguido de su contador. El contador se escribe siempre, también cuando es 1.

Ejemplos:

EntradaSalida
aaabbca3b2c1
aa1

Los contadores llegan a dos cifras: un tramo de 10 letras iguales se escribe a10, dos caracteres de salida para un tramo de 10 — ese es todo el punto de comprimir.

Tu solución

main.cpp — tu solución
Entrada personalizada para «Ejecutar mi entrada»

La corrección corre en tu navegador contra pruebas ocultas. Un bucle infinito se corta a los 3 segundos — aun así, asegúrate de que todo bucle tenga salida. Tu código se guarda solo mientras escribes.

¿Atascado? Pistas

Pista 1 — El tramo se cierra solo

Colócate en la posición i y cuenta mientras s[i] == c. Cuando el bucle de conteo sale, i ya apunta al primer carácter del siguiente tramo — no hay nada que saltar ni rebobinar; solo reiniciar el contador. Un puntero por toda la cadena, nunca hacia atrás.

Pista 2 — Los contadores se escriben como números

cout << contador maneja una, dos o tres cifras — no hace falta partir dígitos a mano, ese era el trabajo del problema de binario. Pero ojo con lo que sí exige: escribir el contador también cuando es 1. Dar abc para abc parece natural y está mal.

Pista 3 — Lee la línea entera

Una vuelta más a la lección de cin.getline: aquí no hay espacios, pero sigue siendo el lector correcto para una línea que hay que tomar entera — y no deja ningún Enter detrás que envenene una lectura posterior. El argumento completo está en Invertir el orden de las palabras.

Solución (¡inténtalo primero!)
#include <iostream>
using namespace std;

int main() {
    char s[205];
    cin.getline(s, 205);

    int i = 0;
    while (s[i] != '\0') {
        char c = s[i];
        int count = 0;
        while (s[i] == c) {
            count++;
            i++;
        }
        cout << c << count;
    }
    cout << endl;
    return 0;
}

La codificación por longitud es la antepasada de la compresión real (vive dentro del fax, JPEG y PNG), y aquí es además otra vez el patrón de autómata sobre cadenas: una bandera, un contador, sin mirar adelante. Su prima contadora — tramos de una *clase* en vez de tramos de un *carácter* — es Contar palabras.

Análisis profundo

Por qué funciona

Un único puntero hacia adelante con un conteo interno que se autotermina: en cuanto s[i] deja de ser c, i ya está en el siguiente tramo. Sin segundo índice, sin mirar adelante, sin segunda pasada — el contador es el bucle interno y la cadena segmenta sola.

El coste

O(L) de tiempo para una línea de L caracteres — cada carácter lo visita exactamente una vez el puntero exterior — y O(L) de espacio para la salida, que aquí nunca supera la entrada.

Dónde falla

  • Omitir el contador cuando es 1 parece más limpio y está mal: la especificación dice escribirlo siempre, y 'a' debe salir como a1.
  • Leer con cin >> se pararía en el primer espacio (aquí no hay, pero el hábito importa) — y lo importante es que getline es el lector de línea entera que este formato presupone.
  • No hace falta separador entre el contador y el siguiente carácter — el formato es carácter seguido inmediatamente de dígitos.

Siguiente paso

El mismo escaneo de una bandera y un contador, contando tramos de una *clase* (espacios) en vez de de un carácter, es Contar palabras.

Dos cosas para recordar

  • El bucle de conteo interno ES la segmentación — i aterriza gratis en el siguiente tramo.
  • Escribe el contador siempre, también 1; cout maneja las cifras múltiples.
🐞 Esta versión falla: ábrela y pruébala

Se salta el contador cuando es 1 — el juez quiere a1, no a

#include <iostream>
using namespace std;

int main() {
    char s[205];
    cin.getline(s, 205);
    int i = 0;
    while (s[i] != '\0') {
        char c = s[i];
        int count = 0;
        while (s[i] == c) {
            count++;
            i++;
        }
        cout << c;
        if (count > 1) cout << count;   // bug: count of 1 is required too
    }
    cout << endl;
    return 0;
}