Coding Interview Prep · Leçon

Recherche de préfixes et Starts-With

Ajoutez une méthode starts_with qui renvoie true si un mot inséré partage un préfixe donné, puis utilisez-la pour implémenter des suggestions de saisie semi-automatique.

Leçon 2 sur 413 étapes

Recherche de préfixes et Starts-With est une leçon Coding Interview Prep gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Coding Interview Prep, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Coding Interview Prep comprend 4 leçons au total.

La puissance des requêtes de préfixe

L’avantage déterminant du Trie par rapport à une table de hachage est l’efficacité des requêtes de préfixe. Une requête de préfixe répond à des questions telles que : « combien de mots stockés commencent par ce préfixe ? », « quels sont tous les mots stockés qui possèdent ce préfixe ? » ou simplement « existe-t-il un mot qui possède ce préfixe ? ». Ces requêtes s’effectuent en O(p), où p est la longueur du préfixe, indépendamment du nombre total de mots stockés — ce qui rend les Trie idéaux pour autocomplete et les suggestions de recherche.

La méthode starts_with

starts_with(prefix) renvoie vrai si un mot stocké commence par le préfixe donné. Parcourez le Trie en suivant chaque caractère du préfixe. Si tous les caractères peuvent être suivis sans rencontrer d’arête manquante, le préfixe existe et au moins un mot commence par celui-ci. L’implémentation est identique à celle de search, sauf que nous renvoyons vrai dès que le parcours est terminé : nous ne vérifions pas 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'))   # False

Autocomplete : trouver tous les mots ayant un préfixe

Pour implémenter autocomplete, parcourez le Trie jusqu’au nœud qui termine le préfixe, puis effectuez un DFS ou un BFS depuis ce nœud afin de recueillir tous les mots qui en partent. Ajoutez le préfixe au début de chaque suffixe recueilli pour reconstruire les mots complets. Cette opération s’effectue en O(p + W), où W est le nombre total de caractères dans tous les mots correspondants.

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']

Renvoyer les suggestions triées

Pour une autocomplete triée, parcourez les enfants dans l’ordre alphabétique pendant le DFS, en itérant sur sorted(node.children.items()). Comme les enfants sont stockés dans un dictionnaire, cela ajoute une surcharge de O(taille de l’alphabet × profondeur), mais garantit des résultats classés dans l’ordre lexicographique. Un Trie fondé sur un tableau parcourt toujours les enfants dans l’ordre alphabétique, puisque les indices 0 à 25 sont ordonnés.

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')

Suggestions autocomplete parmi les meilleures K

Pour obtenir les meilleures K suggestions selon la fréquence, ajoutez à chaque nœud un compteur du nombre de fois où le mot qui se termine à cet endroit a été recherché. Lors de la collecte des suggestions, utilisez un tas max de taille k. Cela réduit l’ensemble des résultats du DFS, en O(W), à O(k), sans matérialiser toutes les correspondances. Les moteurs de recherche réels combinent le parcours des préfixes d’un Trie avec des données de fréquence pour fournir rapidement des suggestions pertinentes.

Implémenter le Trie pour LeetCode 208

Le problème LeetCode 208, « Implémenter un Trie (arbre de préfixes) », demande exactement : insert(word), search(word), qui renvoie un booléen de correspondance exacte, et startsWith(prefix), qui renvoie un booléen de correspondance de préfixe. Il s’agit de l’implémentation canonique d’un Trie. N’oubliez pas : search exige is_end=True ; startsWith exige seulement que le chemin du préfixe existe.

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'))   # True

Utiliser « # » comme marqueur de fin (Trie avec dictionnaire)

Une astuce élégante consiste à stocker le Trie sous forme de dictionnaires imbriqués, avec une clé sentinelle spéciale comme '#' pour marquer la fin des mots, ce qui élimine le besoin d’une classe TrieNode. Cette solution est compacte et adaptée aux entretiens, mais légèrement moins lisible que des objets TrieNode explicites. Les deux implémentations sont acceptables ; la version avec dictionnaire est plus rapide à écrire sous pression.

Préfixe commun le plus long avec un Trie

Pour trouver le préfixe commun le plus long d’une liste de chaînes, insérez toutes les chaînes dans le Trie, puis parcourez celui-ci depuis la racine en suivant l’unique chemin qui existe tant que : (1) le nœud courant possède exactement un enfant et (2) is_end vaut faux. Arrêtez-vous dès que l’une de ces conditions n’est plus satisfaite. Le chemin suivi est le préfixe commun le plus long.

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']))     # ''

Problème Remplacer les mots

Remplacer les mots (LeetCode 648) : étant donné un dictionnaire de mots racines et une phrase, remplacez chaque mot de la phrase par la racine correspondante la plus courte du dictionnaire. Insérez toutes les racines dans un Trie. Pour chaque mot de la phrase, parcourez le Trie jusqu’à trouver la fin d’une racine, puis renvoyez cette racine comme remplacement. Si aucune racine ne correspond, conservez le mot d’origine. Cette méthode s’exécute en O(nombre total de caractères), contre O(n × m) pour la force brute.

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'))

Problème des paires somme de mappage

Somme de mappage (LeetCode 677) : insérez des paires clé-valeur et renvoyez la somme de toutes les valeurs dont les clés possèdent un préfixe donné. Ajoutez à chaque TrieNode un champ val. Pour insert, parcourez le Trie jusqu’à la fin et définissez la valeur ; pour les requêtes de somme, parcourez le Trie jusqu’au nœud qui termine le préfixe et calculez avec DFS la somme de tous les champs val situés en dessous. Vous pouvez aussi stocker la somme cumulée dans chaque nœud lors de l’insertion afin d’obtenir des requêtes en O(p).

Implémentation de la saisie semi-automatique avec un nombre limité de résultats

Dans les systèmes de saisie semi-automatique en production, renvoyer tous les mots correspondant à un préfixe est impraticable lorsque des milliers de mots correspondent. Utilisez plutôt un tas maximal de taille k pendant le parcours DFS : conservez les k mots ayant les scores les plus élevés parmi ceux trouvés jusqu'à présent. Arrêtez prématurément les branches du parcours DFS si elles ne peuvent manifestement pas contenir un mot parmi les k meilleurs (élagage selon une borne supérieure du score). Cela donne une complexité de O(p + k × log k) par requête pour k suggestions — bien meilleure que la collecte de toutes les correspondances.

Vérification rapide

Testez votre compréhension des concepts de structures de données et d'algorithmes — préparation aux entretiens de programmation présentés dans cette leçon.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris que starts_with parcourt le chemin du préfixe et renvoie True s'il existe — aucune vérification de is_end n'est nécessaire, que la saisie semi-automatique par DFS collecte tous les mots à partir du nœud terminal du préfixe en ajoutant des caractères au fur et à mesure de la descente, et que l'ajout de compteurs ou de valeurs aux nœuds permet d'effectuer des requêtes de somme et de proposer les k meilleures suggestions. Ensuite, nous ajouterons la recherche avec caractères génériques et expressions régulières dans le trie.

Gratuit pour commencer

Apprends Coding Interview Prep avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
90
Leçons
360

Questions Fréquemment Posées

La leçon « Recherche de préfixes et Starts-With » est-elle gratuite ?

Oui — le texte complet de « Recherche de préfixes et Starts-With » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Coding Interview Prep, passe à CoddyKit PRO. Le cours Coding Interview Prep comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Recherche de préfixes et Starts-With » ?

Ajoutez une méthode starts_with qui renvoie true si un mot inséré partage un préfixe donné, puis utilisez-la pour implémenter des suggestions de saisie semi-automatique. Tu pratiques Coding Interview Prep avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Coding Interview Prep ?

Aucune expérience préalable n'est requise. Coding Interview Prep sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Recherche de préfixes et Starts-With » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Coding Interview Prep ?

Oui. Chaque leçon Coding Interview Prep inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Classe TrieNode : insertion et recherche
  2. Recherche de préfixes et Starts-With
  3. Recherche avec caractères génériques et expressions régulières dans un trie
  4. Recherche de mots II : trie et retour arrière sur une grille
← Retour à Coding Interview Prep