DSA Interview Prep · Lektion

Prefixsökning och Starts-With

Lägg till en starts_with-metod som returnerar true om något infogat ord delar ett angivet prefix och använd den för att implementera förslag på automatisk komplettering.

Lektion 2 av 413 steg

Prefixsökning och Starts-With är en gratis lektion i DSA Interview Prep på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för DSA Interview Prep, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i DSA Interview Prep innehåller totalt 4 lektioner.

Prefixfrågornas styrka

Triets främsta fördel jämfört med en hash map är effektiv prefixsökning. En prefixfråga kan besvara: ”hur många lagrade ord börjar med det här prefixet?”, ”vilka är alla lagrade ord med det här prefixet?” eller helt enkelt ”finns det något ord med det här prefixet?”. Dessa frågor har O(p)-komplexitet, där p är prefixets längd, oberoende av det totala antalet lagrade ord — vilket gör tries idealiska för autocomplete och sökförslag.

Metoden starts_with

starts_with(prefix) returnerar True om något lagrat ord börjar med det angivna prefixet. Gå igenom trien genom att följa varje tecken i prefixet. Om alla tecken kan följas utan att någon kant saknas finns prefixet, och minst ett ord börjar med det. Implementationen är identisk med search, förutom att vi returnerar True så snart genomgången är klar — vi kontrollerar inte 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: hitta alla ord med ett prefix

För att implementera autocomplete går du till prefixets slutnod och gör sedan en DFS eller BFS från den noden för att samla in alla ord som grenar ut från den. Lägg till prefixet framför varje insamlat suffix för att återskapa de fullständiga orden. Detta tar O(p + W) tid, där W är det totala antalet tecken i alla matchande ord.

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

Returnera sorterade förslag

För sorterade autocomplete-förslag går du igenom barnen i alfabetisk ordning under DFS, genom att iterera över sorted(node.children.items()). Eftersom barnen lagras i en dictionary tillkommer overhead på O(ALPHABET_SIZE × depth), men resultaten garanteras komma i lexikografisk ordning. En arraybaserad trie går alltid igenom barnen i alfabetisk ordning, eftersom indexen 0–25 är ordnade.

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

Autocomplete-förslag med topp-k

För topp-k-förslag efter frekvens utökar du varje nod med ett antal som anger hur många gånger ordet som slutar där har sökts efter. När du samlar in förslag använder du en max-heap med storleken k. Detta minskar resultatmängden från DFS, O(W), till O(k) utan att materialisera alla matchningar. Sökmotorer i verkligheten kombinerar triegenomgång av prefix med frekvensdata för att snabbt skapa relevanta förslag.

Implementera trien för LeetCode 208

LeetCode 208, 'Implement Trie (Prefix Tree)', kräver exakt följande: insert(word), search(word) som returnerar ett booleskt värde för exakt matchning, och startsWith(prefix) som returnerar ett booleskt värde för prefixmatchning. Detta är den klassiska trie-implementeringen. Kom ihåg: search kräver is_end=True; startsWith kräver endast att prefixvägen finns.

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

Använda '#' som slutmarkör (dictionary-trie)

En elegant genväg är att lagra trien som nästlade dictionary-objekt med en särskild sentinel-nyckel, till exempel '#', för att markera ordslut. Då behövs ingen TrieNode-klass. Detta är kompakt och passar bra i intervjuer, men är något mindre läsbart än explicita TrieNode-objekt. Båda implementationerna är godtagbara; dictionary-versionen går snabbare att skriva under tidspress.

Längsta gemensamma prefix med trie

För att hitta det längsta gemensamma prefixet i en lista med strängar infogar du alla strängar i trien och går sedan från roten längs den enda väg som finns så länge som: (1) den aktuella noden har exakt ett barn och (2) is_end är False. Stanna så snart något av villkoren inte längre gäller. Den följda vägen är det längsta gemensamma prefixet.

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

Problemet Replace Words

Replace Words (LeetCode 648): givet en dictionary med rotord och en mening ska du ersätta varje ord i meningen med det kortaste matchande rotordet från dictionaryn. Infoga alla rotord i en trie. För varje ord i meningen går du igenom trien tills slutet på ett rotord hittas — returnera då det rotordet som ersättning. Om inget rotord matchar behåller du det ursprungliga ordet. Detta körs på O(total chars) jämfört med O(n × m) för brute force.

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

Problemet Map Sum Pairs

Map Sum (LeetCode 677): infoga nyckel-värde-par och returnera summan av alla värden vars nycklar har ett givet prefix. Utöka varje TrieNode med ett val-fält. Vid insert går du till slutet och anger värdet; vid sum-frågor går du till prefixets slutnod och summerar alla val-fält under den med DFS. Alternativt kan du lagra den kumulativa summan i varje nod under insättningen för frågor med O(p)-komplexitet.

Implementering av autocomplete med begränsat antal resultat

I produktionssystem för autocomplete är det opraktiskt att returnera alla ord med ett visst prefix när tusentals ord matchar. Använd i stället en max-heap med storleken k under DFS-genomgången: håll reda på de k ord med högst poäng som hittats hittills. Avsluta DFS-grenar tidigt om de omöjligen kan innehålla ett ord bland de k bästa (beskärning utifrån en övre gräns för poängen). Då blir tidskomplexiteten O(p + k × log k) per fråga för k förslag — mycket bättre än att samla in alla träffar.

Snabbkontroll

Testa dina kunskaper om koncepten i Data Structures & Algorithms — Coding Interview Prep från den här lektionen.

Sammanfattning av lektionen

I den här lektionen lärde du dig: starts_with går igenom prefixvägen och returnerar True om den finns — någon is_end-kontroll behövs inte, autocomplete-DFS samlar in alla ord från prefixets slutnod genom att lägga till tecken när den går nedåt, och att utöka noder med antal eller värden möjliggör summationsfrågor och top-k-förslag. Nästa steg är att lägga till matchning med jokertecken och reguljära uttryck i trien.

Gratis att börja

Lär dig Python med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
30
Lektioner
120

Vanliga frågor

Är lektionen ”Prefixsökning och Starts-With” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen DSA Interview Prep, inklusive ”Prefixsökning och Starts-With”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i DSA Interview Prep innehåller totalt 4 lektioner.

Vad lär jag mig i ”Prefixsökning och Starts-With”?

Lägg till en starts_with-metod som returnerar true om något infogat ord delar ett angivet prefix och använd den för att implementera förslag på automatisk komplettering. Ni övar på DSA Interview Prep med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig DSA Interview Prep?

Du behöver inga förkunskaper. Utbildningen i DSA Interview Prep på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Prefixsökning och Starts-With”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här DSA Interview Prep-lektionen?

Ja. Varje DSA Interview Prep-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. TrieNode-klassen: infogning och sökning
  2. Prefixsökning och Starts-With
  3. Wildcard- och regexsökning i ett trie
  4. Word Search II: trie och backtracking i ett rutnät
← Tillbaka till DSA Interview Prep