La secuencia count-and-say es una serie de números enteros que inicia así: 1, 11, 21, 1211, 111221, ...
Se interpreta como: 1 se lee como "un 1" → 11; 11 se lee como "dos 1s" → 21; 21 se lee como "un 2, luego un 1" → 1211.
Dado un entero n, el objetivo es generar la n-ésima secuencia, representada como una cadena de caracteres.
A continuación, se presentan varias implementaciones en C++ para resolver este problema.
class Solucion {
public:
string generarSiguiente(const string &entrada) {
stringstream flujo;
int repeticiones = 0;
char caracterActual = entrada[0];
for (size_t pos = 0; pos <= entrada.size(); ++pos) {
if (caracterActual == entrada[pos]) {
++repeticiones;
} else {
flujo << repeticiones << caracterActual;
repeticiones = 1;
caracterActual = entrada[pos];
}
}
return flujo.str();
}
string countAndSay(int n) {
if (n <= 0) return "";
string resultado = "1";
for (int paso = 1; paso < n; ++paso) {
resultado = generarSiguiente(resultado);
}
return resultado;
}
};
Otra aproximación utiliza un bucle while para procesar la cadena:
class Solucion {
public:
string siguienteLectura(const string &s) {
stringstream flujo;
int conteo, idx = 0, longitud = s.length();
while (idx < longitud) {
conteo = 0;
while (idx + 1 < longitud && s[idx] == s[idx + 1]) {
idx++;
conteo++;
}
flujo << conteo + 1 << s[idx];
idx++;
}
return flujo.str();
}
string countAndSay(int n) {
string res = "";
if (n == 0) return res;
res = "1";
if (n == 1) return "1";
while (n > 1) {
res = siguienteLectura(res);
n--;
}
return res;
}
};
Una implementación alternativa emplea bucles anidados para contar caracteres consecutivos:
class Solucion {
public:
string countAndSay(int n) {
if (n == 0) return NULL;
if (n == 1) return "1";
int contador = 1;
string cadenaActual = "1";
string cadenaSiguiente;
int iterador = 1;
if (n >= 2) {
cadenaActual = "11";
iterador = 2;
}
int i = 0;
while (iterador < n && n > 1) {
cadenaSiguiente = "";
for (i = 0; i < cadenaActual.size(); i++) {
for (int m = i; m < cadenaActual.size() - 1; m++) {
if (cadenaActual[m] == cadenaActual[m + 1]) {
contador++;
i++;
}
if (cadenaActual[m] != cadenaActual[m + 1]) {
break;
}
}
cadenaSiguiente += to_string(contador) + cadenaActual[i];
contador = 1;
}
cadenaActual = cadenaSiguiente;
iterador++;
}
return cadenaActual;
}
};
Finalmente, una solución compacta utiliza un enfoque iterativo con punteros:
class Solucion {
public:
string countAndSay(int n) {
if (n == 0) return " ";
if (n == 1) return "1";
string base = "1";
string temporal;
for (int i = 1; i < n; ++i) {
temporal.clear();
int repeticiones = 1;
for (int j = 0; j < base.size(); ++j) {
while (j + 1 < base.size()) {
if (base[j] == base[j + 1]) {
++repeticiones;
++j;
} else {
break;
}
}
temporal.push_back(repeticiones + '0');
temporal.push_back(base[j]);
repeticiones = 1;
}
base = temporal;
}
return base;
}
};