Desenrolar é essencialmente correto que existem muitas maneiras diferentes de implementar uma tentativa; e, para uma tentativa grande e escalável, os dicionários aninhados podem se tornar pesados - ou pelo menos ineficientes em termos de espaço. Mas como você está apenas começando, acho que é a abordagem mais fácil; você pode codificar um simples trie
em apenas algumas linhas. Primeiro, uma função para construir o trie:
>>> _end = '_end_'
>>>
>>> def make_trie(*words):
... root = dict()
... for word in words:
... current_dict = root
... for letter in word:
... current_dict = current_dict.setdefault(letter, {})
... current_dict[_end] = _end
... return root
...
>>> make_trie('foo', 'bar', 'baz', 'barz')
{'b': {'a': {'r': {'_end_': '_end_', 'z': {'_end_': '_end_'}},
'z': {'_end_': '_end_'}}},
'f': {'o': {'o': {'_end_': '_end_'}}}}
Se você não estiver familiarizado setdefault
, basta procurar uma chave no dicionário (aqui letter
ou _end
). Se a chave estiver presente, ela retornará o valor associado; caso contrário, atribui um valor padrão a essa chave e retorna o valor ( {}
ou _end
). (É como uma versão get
que também atualiza o dicionário.)
Em seguida, uma função para testar se a palavra está no seguinte:
>>> def in_trie(trie, word):
... current_dict = trie
... for letter in word:
... if letter not in current_dict:
... return False
... current_dict = current_dict[letter]
... return _end in current_dict
...
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'baz')
True
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'barz')
True
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'barzz')
False
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'bart')
False
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'ba')
False
Deixarei inserção e remoção para você como um exercício.
Obviamente, a sugestão de Unwind não seria muito mais difícil. Pode haver uma ligeira desvantagem de velocidade, pois encontrar o subnó correto exigiria uma pesquisa linear. Mas a pesquisa seria limitada ao número de caracteres possíveis - 27, se incluirmos _end
. Além disso, não há nada a ganhar criando uma lista enorme de nós e acessando-os por índice, como ele sugere; você pode apenas aninhar as listas.
Por fim, acrescentarei que a criação de um gráfico de palavras acíclicas direcionadas (DAWG) seria um pouco mais complexa, porque você precisa detectar situações nas quais sua palavra atual compartilha um sufixo com outra palavra na estrutura. De fato, isso pode ficar bastante complexo, dependendo de como você deseja estruturar o DAWG! Talvez você precise aprender algumas coisas sobre a distância de Levenshtein para acertar.