Búsqueda por prefijo y Starts-With
Añada un método starts_with que devuelva true si alguna palabra insertada comparte un prefijo dado y úselo para implementar sugerencias de autocompletado.
Búsqueda por prefijo y Starts-With es una lección gratuita de Coding Interview Prep en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Coding Interview Prep, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Coding Interview Prep incluye 4 lecciones en total.
El poder de las consultas de prefijos
La principal ventaja del Trie frente a una tabla hash son las eficientes consultas de prefijos. Una consulta de prefijo responde a preguntas como: «¿cuántas palabras almacenadas comienzan con este prefijo?», «¿cuáles son todas las palabras almacenadas con este prefijo?» o, sencillamente, «¿existe alguna palabra con este prefijo?». Estas consultas son O(p), donde p es la longitud del prefijo, independientemente del número total de palabras almacenadas, lo que hace que los Tries sean ideales para el autocompletado y las sugerencias de búsqueda.
El método starts_with
starts_with(prefix) devuelve True si alguna palabra almacenada comienza con el prefijo indicado. Recorra el Trie siguiendo cada carácter del prefijo. Si se pueden seguir todos los caracteres sin que falte ninguna arista, el prefijo existe y al menos una palabra comienza con él. La implementación es idéntica a search, salvo que devuelve True en cuanto termina el recorrido: no comprueba is_end.
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for c in word:
if c not in node.children:
node.children[c] = TrieNode()
node = node.children[c]
node.is_end = True
def starts_with(self, prefix):
node = self.root
for c in prefix:
if c not in node.children:
return False
node = node.children[c]
return True
t = Trie()
for w in ['hello','help','world','word']:
t.insert(w)
print(t.starts_with('hel')) # True
print(t.starts_with('wor')) # True
print(t.starts_with('xyz')) # FalseAutocompletado: encontrar todas las palabras con un prefijo
Para implementar el autocompletado, recorra el Trie hasta el nodo final del prefijo y, después, realice un DFS (o BFS) desde ese nodo para recopilar todas las palabras que parten de él. Anteponga el prefijo a cada sufijo recopilado para reconstruir las palabras completas. Es una operación O(p + W), donde W es el número total de caracteres de todas las palabras coincidentes.
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for c in word:
if c not in node.children:
node.children[c] = TrieNode()
node = node.children[c]
node.is_end = True
def autocomplete(self, prefix):
node = self.root
for c in prefix:
if c not in node.children:
return []
node = node.children[c]
# DFS from prefix end node
results = []
def dfs(n, path):
if n.is_end:
results.append(prefix + path)
for char, child in n.children.items():
dfs(child, path + char)
dfs(node, '')
return results
t = Trie()
for w in ['apple','app','application','apply','apt']:
t.insert(w)
print(t.autocomplete('app')) # ['app','apple','apply','application']Devolver sugerencias ordenadas
Para obtener un autocompletado ordenado, recorra los hijos en orden alfabético durante el DFS (itere sobre sorted(node.children.items())). Como los hijos se almacenan en un diccionario, esto añade una sobrecarga de O(ALPHABET_SIZE × depth), pero garantiza resultados ordenados lexicográficamente. Un Trie basado en arreglos siempre recorre los hijos en orden alfabético, ya que los índices del 0 al 25 están ordenados.
def dfs_sorted(node, prefix, results):
if node.is_end:
results.append(prefix)
for char in sorted(node.children.keys()): # alphabetical order
dfs_sorted(node.children[char], prefix + char, results)
print('Iterating children in sorted order gives lex-sorted suggestions')Sugerencias de autocompletado Top-K
Para obtener las k mejores sugerencias por frecuencia, añada a cada nodo un contador del número de veces que se ha buscado la palabra que termina en él. Al recopilar las sugerencias, utilice un montículo máximo de tamaño k. Esto reduce a O(k) el conjunto de resultados del DFS, que sería de O(W), sin materializar todas las coincidencias. Los motores de búsqueda reales combinan el recorrido de prefijos del Trie con datos de frecuencia para ofrecer sugerencias rápidas y relevantes.
Implementar el Trie para LeetCode 208
LeetCode 208, «Implement Trie (Prefix Tree)», solicita exactamente: insert(word), search(word), que devuelve un booleano de coincidencia exacta, y startsWith(prefix), que devuelve un booleano de coincidencia de prefijo. Esta es la implementación canónica de un Trie. Recuerde: search requiere is_end=True; startsWith solo requiere que exista la ruta del prefijo.
class Trie:
def __init__(self):
self.root = {}
def insert(self, word):
node = self.root
for c in word:
if c not in node:
node[c] = {}
node = node[c]
node['#'] = True # '#' marks word end
def search(self, word):
node = self.root
for c in word:
if c not in node: return False
node = node[c]
return '#' in node
def startsWith(self, prefix):
node = self.root
for c in prefix:
if c not in node: return False
node = node[c]
return True
t = Trie()
t.insert('apple')
print(t.search('apple')) # True
print(t.search('app')) # False
print(t.startsWith('app')) # TrueUsar '#' como marcador de final (Trie con diccionario)
Una alternativa elegante consiste en almacenar el Trie como diccionarios anidados con una clave especial centinela, como '#', para marcar los finales de las palabras, eliminando la necesidad de una clase TrieNode. Es una opción compacta y adecuada para entrevistas, aunque ligeramente menos legible que los objetos TrieNode explícitos. Ambas implementaciones son válidas; la versión con diccionario se escribe más rápido cuando hay presión de tiempo.
Prefijo común más largo con un Trie
Para encontrar el prefijo común más largo de una lista de cadenas, inserte todas las cadenas en el Trie y recorra desde la raíz siguiendo la única ruta existente mientras se cumplan estas condiciones: (1) el nodo actual tiene exactamente un hijo y (2) is_end es False. Deténgase cuando deje de cumplirse cualquiera de las condiciones. La ruta seguida es el prefijo común más largo.
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
def longest_common_prefix(words):
root = TrieNode()
for word in words:
node = root
for c in word:
if c not in node.children:
node.children[c] = TrieNode()
node = node.children[c]
node.is_end = True
prefix = []
node = root
while len(node.children) == 1 and not node.is_end:
char, node = next(iter(node.children.items()))
prefix.append(char)
return ''.join(prefix)
print(longest_common_prefix(['flower','flow','flight'])) # 'fl'
print(longest_common_prefix(['dog','racecar','car'])) # ''Problema Replace Words
Replace Words (LeetCode 648): dado un diccionario de palabras raíz y una oración, reemplace cada palabra de la oración por la raíz coincidente más corta del diccionario. Inserte todas las raíces en un Trie. Para cada palabra de la oración, recorra el Trie hasta encontrar el final de una raíz y devuelva esa raíz como reemplazo. Si no coincide ninguna raíz, conserve la palabra original. Esto se ejecuta en O(total chars), frente a O(n × m) mediante fuerza bruta.
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
def replaceWords(dictionary, sentence):
root = TrieNode()
for word in dictionary:
node = root
for c in word:
if c not in node.children:
node.children[c] = TrieNode()
node = node.children[c]
node.is_end = True
def find_root(word):
node = root
for i, c in enumerate(word):
if c not in node.children: break
node = node.children[c]
if node.is_end:
return word[:i+1]
return word
return ' '.join(find_root(w) for w in sentence.split())
print(replaceWords(['cat','bat','rat'], 'the cattle was rattled by the battery'))Problema Map Sum Pairs
Map Sum (LeetCode 677): inserte pares clave-valor y devuelva la suma de todos los valores cuyas claves tienen un prefijo determinado. Añada a cada TrieNode un campo val. Para insert, recorra el Trie hasta el final y establezca el valor; para las consultas de suma, recorra el Trie hasta el nodo final del prefijo y calcule mediante DFS la suma de todos los campos val que hay debajo. Como alternativa, almacene la suma acumulada en cada nodo durante la inserción para realizar consultas en O(p).
Implementar autocompletado con resultados limitados
En los sistemas de autocompletado en producción, devolver todas las palabras con un prefijo no es práctico cuando coinciden miles de palabras. En su lugar, use un max-heap de tamaño k durante el recorrido DFS: mantenga las k palabras con mayor puntuación encontradas hasta el momento. Detenga pronto las ramas del DFS si no pueden contener una palabra del top-k (poda mediante una cota superior de puntuación). De este modo se obtiene O(p + k × log k) por consulta para k sugerencias, mucho mejor que recopilar todas las coincidencias.
Comprobación rápida
Ponga a prueba su comprensión de los conceptos de Data Structures & Algorithms — Coding Interview Prep de esta lección.
Resumen de la lección
En esta lección aprendió: starts_with recorre la ruta del prefijo y devuelve True si existe; no es necesario comprobar is_end, el DFS de autocomplete recopila todas las palabras desde el nodo final del prefijo añadiendo caracteres a medida que desciende, y ampliar los nodos con recuentos o valores permite realizar consultas de suma y obtener sugerencias top-k. A continuación añadiremos la búsqueda con comodines y expresiones regulares al trie.
Preguntas frecuentes
¿La lección «Búsqueda por prefijo y Starts-With» es gratis?
Sí — el texto completo de «Búsqueda por prefijo y Starts-With» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Coding Interview Prep, actualiza a CoddyKit PRO. El curso de Coding Interview Prep incluye 4 lecciones en total.
¿Qué aprenderé en «Búsqueda por prefijo y Starts-With»?
Añada un método starts_with que devuelva true si alguna palabra insertada comparte un prefijo dado y úselo para implementar sugerencias de autocompletado. Practicas Coding Interview Prep con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Coding Interview Prep?
No se requiere experiencia previa. Coding Interview Prep en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Búsqueda por prefijo y Starts-With»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Coding Interview Prep?
Sí. Cada lección de Coding Interview Prep incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Clase TrieNode: inserción y búsqueda
- Búsqueda por prefijo y Starts-With
- Búsqueda con comodines y expresiones regulares en un trie
- Word Search II: trie y retroceso en una cuadrícula