Medio · estado de cadena

Contar palabras

El primer problema donde tienes que recordar algo del carácter anterior para decidir qué significa el actual. Eso es una máquina de estados, y está en todas partes.

En una fraseUna palabra es cualquier tramo sin espacios: cuenta las transiciones de espacio a no-espacio, lee con getline (cin >> corta en el primer espacio) y no dejes que los espacios repetidos creen palabras vacías.

El problema

Entrada: Una sola línea de texto, como máximo 200 caracteres. Puede contener letras, puntuación y espacios, incluidos espacios al principio y al final, y varios espacios seguidos.

Salida: El número de palabras, donde una palabra es cualquier secuencia de caracteres que no sean espacios.

Ejemplos:

EntradaSalida
hello world2
a b c 3
0

Léela con cin.getline(s, size), no con cin >> s. Este último se detiene en el primer espacio y te daría una sola palabra para cualquier entrada.

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 — No cuentes palabras: cuenta <em>inicios</em> de palabra

Recorriendo carácter a carácter no ves la palabra entera. Pero sí puedes detectar el instante en que empieza: el carácter actual no es un espacio y el anterior sí lo era. Cada inicio es una palabra.

Pista 2 — Convierte "el anterior era espacio" en una variable

bool inWord = false;: ¿estoy dentro de una palabra? Con un espacio, ponlo a false. Con cualquier otra cosa, si estaba en false acabas de encontrar una palabra nueva: incrementa el contador y ponlo a true. Esa sola bandera resuelve espacios iniciales, finales y rachas de diez espacios a la vez.

Pista 3 — La respuesta incorrecta tentadora

Contar los espacios y sumar uno. Funciona con hello world y falla con cualquier cosa que tenga un espacio inicial, uno final o dos seguidos, que es la mayoría del texto real. Es el ejemplo clásico de atajo que esconde una suposición sobre la entrada.

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

int main() {
    char s[205];
    cin.getline(s, 205);
    int count = 0;
    bool inWord = false;
    for (int i = 0; s[i] != '\0'; i++) {
        if (s[i] == ' ') {
            inWord = false;
        } else if (!inWord) {
            inWord = true;
            count++;
        }
    }
    cout << count << endl;
    return 0;
}

Cambia s[i] == ' ' por !isalpha(s[i]) y tienes un contador de palabras que ignora la puntuación. Cámbialo por una comprobación contra una lista de separadores y tienes un parser de CSV. El patrón de un booleano que describe dónde estoy, actualizado mientras recorro es como los compiladores hacen análisis léxico, como los editores resaltan sintaxis y como los parsers HTTP encuentran los límites de las cabeceras. Ahora haz que un array se reordene solo en Ordenamiento burbuja.

Análisis profundo

Por qué funciona

Recorriendo carácter a carácter nunca ves una palabra entera, pero sí puedes detectar el instante en que empieza: este carácter no es espacio y el anterior sí. Con un booleano basta.

El coste

O(longitud), más un bool. "Contar los espacios y sumar uno" es más corto de escribir y falla con espacios iniciales, finales y dobles: pagaste ese atajo con corrección.

Dónde falla

  • Leer con cin >> s se detiene en el primer espacio, así que cualquier entrada da una sola palabra.
  • Contar espacios y sumar uno falla en los tres casos a la vez: espacio inicial, final y dos seguidos.

Siguiente paso

Mismo esqueleto de máquina de estados, otro separador, y tienes un parser de CSV. Ahora haz que un array se reordene: Ordenamiento burbuja.

Dos cosas para recordar

  • No cuentes palabras: cuenta dónde empiezan.
  • Un booleano que describe dónde estás, actualizado mientras recorres: eso es una máquina de estados.
🐞 Esta versión falla: ábrela y pruébala

Cuenta espacios y suma uno: falla con espacios iniciales, finales y dobles

#include <iostream>
using namespace std;

int main() {
    char s[205];
    cin.getline(s, 205);
    int count = 1;
    for (int i = 0; s[i] != '\0'; i++) {
        if (s[i] == ' ') count++;
    }
    cout << count << endl;
    return 0;
}