#11 suffix tree es un overkill de la hostia teniendo en cuenta que el alfabeto es binario y la longitud fija y nada grande.
edit: #1 lee parrafo a parrafo para evitar spoilers
Con un array puedes. Una palabra en morse puede interpretarse como un numero en binario en la que los puntos son ceros y los guiones unos. O al reves, a gusto del consumidor.
Si lo miras asi, tienes 2 ** 13 palabras de longitud 13. Haz un array de 2 ** 13 = 8192 posiciones de booleanos y ve marcando trues segun veas las secuencias correspondientes.
Una vez termines el procesado iteras sobre el array y buscas los falses.
Overall complexity: O(n + 8192) = O(n), se puede hacer de una unica pasada si vas cambiando la mascara de bits acumulada bit a bit en lugar de substring a substring. Notemos que hacerlo por substrings no nos hace salirnos de coste lineal al ser 13 una constante.
Espacio adicional necesario (teoricamente podriamos resolverlo leyendo char a char): O(8192) = O(1)
Te dejo mi codigo en spoiler:
spoilerimport sys
S = '.- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --..'.split()
appears = [False] * (1 << 13)
def get_encodings(input_file):
'''Leemos el fichero y devolvemos un array
de strings con las palabras codificadas sin espacios
'''
with open(input_file, 'r') as f:
words = []
for line in f:
words.append(
''.join(
[S[ord(x) - ord('a')] for x in line.strip()]
)
)
return words
def process_sequence(w):
if len(w) >= 13:
# codificamos la primera secuencia (la que va de 0 a 12)
def morse2bit(x):
return int(x == '.')
accum = sum([morse2bit(w[13 - k - 1]) * (2 ** k) for k in range(13)])
appears[accum] = True
# Procesamos el resto de secuencias usando el valor inicial
for i in range(13, len(w)):
# Quitamos el bit mas significativo
# Desplazamos el resto a la izquierda
# Y ponemos el bit actual
accum = ((accum << 1) & (2 ** 13 - 1)) | morse2bit(w[i])
appears[accum] = True
def main():
input_file = sys.argv[1]
seqs = get_encodings(input_file)
for seq in seqs:
process_sequence(seq)
for (i, v) in enumerate(appears):
if not v:
print(
''.join(
['.' if ((i & (1 << k)) != 0) else '-' for k in range(13)]
)
)
if __name__ == '__main__':
main()
Y las palabras que me da de resultado:
spoilertime python morse.py enable1.txt
----.----.---
-----.---.---
-.---.---.---
------.---.--
--.---.---.--
python morse.py enable1.txt 2.15s user 0.04s system 99% cpu 2.200 total