Ricerca con caratteri jolly ed espressioni regolari in un trie
Supporti la corrispondenza con il carattere jolly '.' esplorando tutti i figli a quella profondità e risolva il problema della struttura dati design-add-and-search-words.
Ricerca con caratteri jolly ed espressioni regolari in un trie è una lezione DSA Interview Prep gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento DSA Interview Prep, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso DSA Interview Prep include 4 lezioni in totale.
Il problema della ricerca con caratteri jolly
La ricerca standard in un trie gestisce caratteri esatti. La ricerca con caratteri jolly aggiunge un carattere speciale '.' che corrisponde a un singolo carattere qualsiasi. Quando durante la ricerca si incontra '.', invece di seguire un unico figlio specifico, è necessario provare tutti i figli: si verifica un fan-out. Questa è l'idea fondamentale alla base di LeetCode 211 'Design Add and Search Words Data Structure'. Ogni '.' moltiplica i percorsi di ricerca per il numero di figli presenti a quel livello.
Ricerca ricorsiva con caratteri jolly
Si implementi la ricerca con caratteri jolly utilizzando un helper DFS ricorsivo. Per ogni carattere del pattern: se è un carattere letterale, si segua il figlio specifico (oppure si restituisca False se manca); se è '.', si richiami la funzione ricorsivamente su tutti i figli e si restituisca True se una delle chiamate ha successo. Al termine del pattern, si restituisca node.is_end.
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
class WordDictionary:
def __init__(self):
self.root = TrieNode()
def addWord(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 search(self, word):
def dfs(node, i):
if i == len(word):
return node.is_end
c = word[i]
if c == '.':
return any(dfs(child, i+1) for child in node.children.values())
if c not in node.children:
return False
return dfs(node.children[c], i+1)
return dfs(self.root, 0)
wd = WordDictionary()
wd.addWord('bad')
wd.addWord('dad')
wd.addWord('mad')
print(wd.search('.ad')) # True
print(wd.search('b..')) # True
print(wd.search('pad')) # FalsePerché usare any() per il fan-out
Quando si incontra '.', si chiama any(dfs(child, i+1) for child in node.children.values()). Il generatore any() utilizza una valutazione short-circuit: si interrompe non appena un figlio restituisce True. Questo evita esplorazioni non necessarie. Nel caso peggiore (un pattern composto interamente da '.'), vengono esplorati tutti i percorsi: la complessità è O(26^k), dove k è il numero di punti, rendendo pattern come '....' costosi nei trie di grandi dimensioni.
Ricerca iterativa con caratteri jolly mediante code
Un approccio iterativo utilizza una coda di coppie (node, index). Si inizia con (root, 0). Per ogni coppia, se index == len(word) e node.is_end, si restituisce True. Altrimenti si elabora il carattere corrente: per '.' si accodano tutti i figli; per un carattere letterale si accoda solo il figlio corrispondente. Si tratta essenzialmente di un BFS sui percorsi del trie.
from collections import deque
def search_iterative(root, word):
queue = deque([(root, 0)])
while queue:
node, i = queue.popleft()
if i == len(word):
if node.is_end:
return True
continue
c = word[i]
if c == '.':
for child in node.children.values():
queue.append((child, i+1))
elif c in node.children:
queue.append((node.children[c], i+1))
return False
print('Iterative BFS-based wildcard search')Analisi della complessità della ricerca con caratteri jolly
Per un pattern senza caratteri jolly, la ricerca è O(m). Per un pattern con k caratteri jolly, il caso peggiore è O(26^k × m): la complessità è esponenziale rispetto al numero di caratteri jolly. Nella pratica, i caratteri jolly sono generalmente pochi e il trie è poco profondo, quindi le prestazioni sono accettabili. Per pattern composti interamente da caratteri jolly (ad esempio, che corrispondono a tutte le parole di lunghezza k), la ricerca si riduce all'attraversamento completo del trie.
Ricerca con espressioni regolari oltre i caratteri jolly singoli
Estendere la ricerca alle espressioni regolari complete (ad esempio, con '*' che corrisponde a zero o più caratteri) richiede una gestione diversa. '*' può corrispondere a qualsiasi suffisso, quindi quando lo si incontra è necessario provare tutti i percorsi del trie a partire dal nodo corrente. La corrispondenza tramite vere espressioni regolari in un trie è complessa e viene generalmente riservata alle costruzioni NFA/DFA. Nei colloqui tecnici, il pattern standard è il carattere jolly singolo ('.').
Corrispondenza dei pattern glob
La corrispondenza glob con '?' (un carattere qualsiasi) e '*' (una sequenza qualsiasi, anche vuota) può essere implementata con la programmazione dinamica. Se viene implementata in un trie, '?' corrisponde a un fan-out su un singolo livello (come '.') e '*' corrisponde a una DFS su più livelli. L'approccio DP combinato definisce dp[i][j] = True se pattern[0..i] corrisponde a string[0..j]. In genere l'intervistatore specifica quale variante implementare.
Applicazione pratica: instradamento degli indirizzi IP
I trie con caratteri jolly vengono utilizzati nelle tabelle di routing IP, dove '*' funge da carattere jolly per il prefisso. Un router memorizza prefissi di route come '192.168.*' e li confronta con gli indirizzi in ingresso. La corrispondenza del prefisso più lungo (vince la route più specifica) viene implementata attraversando il trie il più in profondità possibile e utilizzando l'ultima corrispondenza trovata. Questa è un'applicazione reale delle operazioni sui prefissi e sui caratteri jolly dei trie.
Ottimizzazione: potatura dei rami inattivi
Quando un nodo del trie non ha figli (è una foglia) e is_end = False, qualsiasi ricerca che lo raggiunga restituisce False. Durante la ricerca con caratteri jolly, ignorare questi nodi terminali prima della ricorsione può eliminare chiamate non necessarie. Mantenere un word_count in ogni nodo, contenente il numero totale di parole nel sottoalbero, consente di ignorare un intero sottoalbero se nessuna parola può soddisfare i vincoli sulla lunghezza rimanente del pattern.
Classe WordDictionary completa, pronta per un colloquio tecnico
Una classe WordDictionary pulita e pronta per un colloquio tecnico, che combina l'inserimento e la ricerca con il carattere jolly punto in un'unica classe. Questa è l'implementazione esatta prevista per LeetCode 211. La ricerca ricorsiva con any() e valutazione short-circuit è concisa e dimostra chiaramente agli intervistatori la logica del fan-out.
class WordDictionary:
def __init__(self):
self.root = {}
def addWord(self, word):
node = self.root
for c in word:
node = node.setdefault(c, {})
node['#'] = True
def search(self, word):
def dfs(node, i):
if i == len(word):
return '#' in node
if word[i] == '.':
return any(dfs(v, i+1) for k, v in node.items() if k != '#')
nxt = node.get(word[i])
return dfs(nxt, i+1) if nxt is not None else False
return dfs(self.root, 0)
wd = WordDictionary()
for w in ['at','and','an','add']:
wd.addWord(w)
print(wd.search('a.')) # True (at, an)
print(wd.search('.nd')) # True (and)
print(wd.search('...')) # True (and, add)
print(wd.search('x.')) # FalseUtilizzare setdefault per un trie compatto
dict.setdefault(key, default) restituisce il valore associato a key se presente; altrimenti inserisce default e lo restituisce. Utilizzare node.setdefault(c, {}) durante l'inserimento elimina il controllo if-else: crea il dizionario figlio se manca e lo restituisce in ogni caso. In questo modo l'inserimento diventa un attraversamento su una sola riga: for c in word: node = node.setdefault(c, {}). Una soluzione pulita e idiomatica in Python.
Verifica rapida
Verifichi la Sua comprensione dei concetti di Data Structures & Algorithms — Coding Interview Prep trattati in questa lezione.
Riepilogo della lezione
In questa lezione ha imparato che: il carattere jolly '.' richiede un fan-out verso tutti i figli nella posizione corrispondente, utilizzando una DFS ricorsiva, l'uso di any() con un generatore fornisce una valutazione short-circuit per terminare in anticipo e setdefault consente un inserimento compatto del trie su una sola riga. Prossimamente combineremo trie e backtracking per risolvere Word Search II, trovando simultaneamente più parole su una griglia 2D.
Domande Frequenti
La lezione «Ricerca con caratteri jolly ed espressioni regolari in un trie» è gratuita?
Sì — il testo completo di «Ricerca con caratteri jolly ed espressioni regolari in un trie» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso DSA Interview Prep, passa a CoddyKit PRO. Il corso DSA Interview Prep include 4 lezioni in totale.
Cosa imparerò in «Ricerca con caratteri jolly ed espressioni regolari in un trie»?
Supporti la corrispondenza con il carattere jolly '.' esplorando tutti i figli a quella profondità e risolva il problema della struttura dati design-add-and-search-words. Eserciti DSA Interview Prep con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare DSA Interview Prep?
Non è richiesta alcuna esperienza precedente. DSA Interview Prep su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Ricerca con caratteri jolly ed espressioni regolari in un trie»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione DSA Interview Prep?
Sì. Ogni lezione DSA Interview Prep include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Classe TrieNode: inserimento e ricerca
- Ricerca per prefisso e Starts-With
- Ricerca con caratteri jolly ed espressioni regolari in un trie
- Word Search II: trie e backtracking su griglia