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:
| Entrada | Salida |
|---|---|
hello world | 2 |
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
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 >> sse 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;
}