Pular para o conteúdo principal
ProdutosFerramentas de desktopTASTECADVisualização de desenhosTASTEFILESGerenciamento de arquivosTASTEFTPTransferência de arquivosTASTESSHEspaço de trabalho remotoTASTEZIPCompactação e extraçãoFerramentas para desenvolvedoresTASTECODEAmbiente de desenvolvimento integrado para RustTASTESTUDIOAmbiente integrado de desenvolvimento e testesTASTEETLIntegração de dados (ETL)ServidoresTASTEREMOTEServidor de área de trabalho remotaTASTEGEOServidor geoespacialTASTEMAILEspaço de trabalho de e-mailComeçarDownloadsDocumentaçãoComprarTodos os produtos
Marketplace
Notícias
TecnologiaNotíciasNotícias de desenvolvimento de hojeDocumentaçãoLinguagens de programaçãoRustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDartFrameworks de front-end webNext.jsReactVue.js · NuxtSvelteKitAngularFrameworks de servidorSpring BootDjangoFastAPIASP.NET CoreNestJS · ExpressFrameworks de apps e desktopTauriFlutterReact NativeElectronAlgoritmosFundamentos de algoritmosAlgoritmos essenciaisAlgoritmos avançadosAlgoritmos práticos
ComunidadeProjetosRegistros de desenvolvimentoPromptsProblemas de ferramentas de IAVitrineGuia da comunidade
ColaboreTransferência técnicaConstrução de siteConstrução de app de desktopPipeline de lançamento e pagamentoParceiro de vendasContato
ServiçosÁrea de trabalho remotaPacotes de instalação sob medida
TASTEDEV
Produtos

Ferramentas de desktop

TASTECADDesenhos complexos, abertos com levezaTASTEFILESSó os arquivos de que você precisa, o mais rápido possívelTASTEFTPO caminho mais organizado para seus arquivosTASTESSHEntre você e o servidor, uma conexão mais sólidaTASTEZIPCompacte mais rápido, extraia com mais segurança

Ferramentas para desenvolvedores

TASTECODEEdite, compile, depure e teste apps Rust em uma única janelaTASTESTUDIODa edição aos testes remotos e às correções com IA aprovadasTASTEETLMova dados de olho nos valores

Servidores

TASTEREMOTEUma área de trabalho remota rodando no seu próprio servidorTASTEGEOUm servidor geoespacial compatível com o GeoServer, reconstruído em RustTASTEMAILRetome o controle do seu e-mail

Começar

DownloadsVersões mais recentes de cada produtoDocsComo usar cada produtoComprarAssinaturas e licenças perpétuasTodos os produtosTodos os produtos de relance
Todos os produtos
MarketplaceNotícias
Tecnologia

Notícias

Notícias de desenvolvimento de hojeAnúncios oficiais de linguagens, frameworks, GitHub e IADocumentaçãoGuias de linguagens, frameworks e algoritmos

Linguagens de programação

RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart

Frameworks

Frameworks de front-end webNext.jsReactVue.js · NuxtSvelteKitAngular
Frameworks de servidorSpring BootDjangoFastAPIASP.NET CoreNestJS · Express
Frameworks de apps e desktopTauriFlutterReact NativeElectron

Algoritmos

Fundamentos de algoritmosAnálise de complexidade · Ordenação · Busca · Estruturas de dados básicas · Árvores e heapsAlgoritmos essenciaisBusca em grafos · Caminho mínimo e árvore geradora mínima · Programação dinâmica · Algoritmos gulosos · Divisão e conquista · BacktrackingAlgoritmos avançadosAlgoritmos de strings · Matemática e teoria dos números · Manipulação de bits · Árvores de segmentos · Union-FindAlgoritmos práticosEstratégia para entrevistas de código · Cache LRU · Limitação de taxa · Hashing consistente
Toda a documentação de desenvolvimento
Comunidade
ProjetosDescubra criadores e trabalhosRegistros de desenvolvimentoDecisões e aprendizadosPromptsInstruções reutilizáveisProblemas de ferramentas de IAProblemas e contornos de Claude, Codex, GeminiVitrineResultados concluídosGuia da comunidadeComo construímos em aberto
Colabore
Transferência técnicaApps nativos em Rust e eguiConstrução de site10 idiomas, contas, documentação e downloadsConstrução de app de desktopRust e egui, sem WebViewPipeline de lançamento e pagamentoAssinatura, MSI, deb, rpm, AppImage, hashesParceiro de vendasRecomende e ganhe 30%ContatoDesenvolvimento, parcerias e investimento
Serviços
Área de trabalho remotaAcesse seu computador pelo navegadorPacotes de instalação sob medidaSó o necessário, configurações pré-carregadas
Comprar
PT
한국어EnglishDeutschEspañolFrançaisItalianoPortuguês (Brasil)日本語简体中文繁體中文
Entrar
Entrar
TASTEDEV

De pequenas ferramentas a um desenvolvimento melhor.

support@tastedev.netApoiar TASTEDEV
ProdutosLinha de produtosComprarDocsDownloadsMarketplaceSuporte
ComunidadeProjetosRegistros de desenvolvimentoPromptsProblemas de ferramentas de IAVitrine
PolíticasPolítica de privacidadeTermos de usoTermos de assinaturaReembolsoDiretrizes da comunidade
ContaEntrarCriar conta
Visitantes
Hoje
012345678901234567890123456789012345678901234567890123456789
Ontem
012345678901234567890123456789012345678901234567890123456789
Visualizações totais
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
Empresa
GXSOFT
Representante
CHOI YOUNG GU
Número de registro comercial
853-44-00368
Endereço
9F V24, 351 Gyeongin-ro, Michuhol-gu, Incheon, Republic of Korea
Telefone
+82-10-4404-1523
E-mail
whitecalvin@tastedev.net
Responsável pela privacidade
CHOI YOUNG GU

© 2026 TASTEDEVAs informações dos produtos se baseiam em fontes de desenvolvimento verificadas.Lançado · em melhoria

Documentação de Algoritmos de strings
Algoritmos de strings
ConceptsHow It WorksImplementationComplexityPractice ProblemsReal-World Use
Discussões

Guia de Algoritmos de strings · 3/6

Implementation

Por enquanto, este capítulo está disponível apenas em inglês.

KMP and a trie in Python, explained, then the same KMP core in C++, Java and TypeScript.

Python: KMP

def prefix_function(p: str) -> list[int]:
    pi = [0] * len(p)                    # pi[i]: longest border of p[:i+1]
    k = 0
    for i in range(1, len(p)):
        while k > 0 and p[i] != p[k]:    # fall back to a shorter border
            k = pi[k - 1]
        if p[i] == p[k]:
            k += 1
        pi[i] = k
    return pi


def kmp_search(text: str, pattern: str) -> list[int]:
    m = len(pattern)
    if m == 0:
        return list(range(len(text) + 1))
    pi = prefix_function(pattern)
    hits, k = [], 0                         # k: matched so far
    for i, ch in enumerate(text):
        while k > 0 and ch != pattern[k]:
            k = pi[k - 1]
        if ch == pattern[k]:
            k += 1
        if k == m:
            hits.append(i - m + 1)
            k = pi[k - 1]                   # allow overlaps
    return hits


assert prefix_function("ababaca") == [0, 0, 1, 2, 3, 0, 1]
assert kmp_search("abababcabab", "abab") == [0, 2, 7]
assert kmp_search("aaaa", "aa") == [0, 1, 2]
  • while shrinks k on a mismatch, if grows it on a match; both functions share this shape.
  • An empty pattern matches everywhere, as with str.find; without the check, pattern[0] fails.
  • i - m + 1 turns the match's end i into its start.

Python: a trie with autocomplete

class TrieNode:
    def __init__(self) -> None:
        self.children: dict[str, "TrieNode"] = {}
        self.is_end = False


class Trie:
    def __init__(self) -> None:
        self.root = TrieNode()

    def insert(self, word: str) -> None:
        node = self.root
        for ch in word:
            node = node.children.setdefault(ch, TrieNode())
        node.is_end = True

    def _walk(self, prefix: str) -> TrieNode | None:
        node = self.root
        for ch in prefix:
            node = node.children.get(ch)
            if node is None:
                return None
        return node

    def complete(self, prefix: str, limit: int = 10) -> list[str]:
        start = self._walk(prefix)
        if start is None:
            return []
        out: list[str] = []
        stack = [(start, prefix)]
        while stack and len(out) < limit:
            node, word = stack.pop()
            if node.is_end:
                out.append(word)
            for ch in sorted(node.children, reverse=True):
                stack.append((node.children[ch], word + ch))
        return out


t = Trie()
for w in ["car", "cart", "cat", "dog"]:
    t.insert(w)
assert t.complete("ca") == ["car", "cart", "cat"]
  • A dict of children works for any alphabet; for lowercase only, 26 slots are faster.
  • Without is_end, the bare prefix would be listed as a word.
Dúvidas sobre este capítulo?
Capítulo anteriorHow It WorksPróximo capítuloComplexity
ca
  • complete uses an explicit stack; children are pushed in reverse so they pop in sorted order.
  • C++

    #include <string>
    #include <vector>
    
    std::vector<int> prefixFunction(const std::string& p) {
        std::vector<int> pi(p.size(), 0);
        int k = 0;
        for (size_t i = 1; i < p.size(); ++i) {
            while (k > 0 && p[i] != p[k]) k = pi[k - 1];
            if (p[i] == p[k]) ++k;
            pi[i] = k;
        }
        return pi;
    }
    
    std::vector<int> kmpSearch(const std::string& text, const std::string& pattern) {
        std::vector<int> hits;
        const int m = static_cast<int>(pattern.size());
        if (m == 0) return hits;
        const std::vector<int> pi = prefixFunction(pattern);
        int k = 0;
        for (size_t i = 0; i < text.size(); ++i) {
            while (k > 0 && text[i] != pattern[k]) k = pi[k - 1];
            if (text[i] == pattern[k]) ++k;
            if (k == m) {
                hits.push_back(static_cast<int>(i) - m + 1);
                k = pi[k - 1];
            }
        }
        return hits;
    }

    std::string holds bytes, so UTF-8 positions are byte offsets. An empty pattern returns nothing here.

    Java

    import java.util.ArrayList;
    import java.util.List;
    
    public final class Kmp {
        static int[] prefixFunction(String p) {
            int[] pi = new int[p.length()];
            int k = 0;
            for (int i = 1; i < p.length(); i++) {
                while (k > 0 && p.charAt(i) != p.charAt(k)) k = pi[k - 1];
                if (p.charAt(i) == p.charAt(k)) k++;
                pi[i] = k;
            }
            return pi;
        }
    
        static List<Integer> search(String text, String pattern) {
            List<Integer> hits = new ArrayList<>();
            int m = pattern.length();
            if (m == 0) return hits;
            int[] pi = prefixFunction(pattern);
            int k = 0;
            for (int i = 0; i < text.length(); i++) {
                while (k > 0 && text.charAt(i) != pattern.charAt(k)) k = pi[k - 1];
                if (text.charAt(i) == pattern.charAt(k)) k++;
                if (k == m) {
                    hits.add(i - m + 1);
                    k = pi[k - 1];
                }
            }
            return hits;
        }
    }

    charAt returns UTF-16 code units: matching stays exact, but positions count code units.

    TypeScript

    export function prefixFunction(p: string): number[] {
      const pi = new Array<number>(p.length).fill(0);
      let k = 0;
      for (let i = 1; i < p.length; i++) {
        while (k > 0 && p[i] !== p[k]) k = pi[k - 1];
        if (p[i] === p[k]) k++;
        pi[i] = k;
      }
      return pi;
    }
    
    export function kmpSearch(text: string, pattern: string): number[] {
      const hits: number[] = [];
      const m = pattern.length;
      if (m === 0) return hits;
      const pi = prefixFunction(pattern);
      let k = 0;
      for (let i = 0; i < text.length; i++) {
        while (k > 0 && text[i] !== pattern[k]) k = pi[k - 1];
        if (text[i] === pattern[k]) k++;
        if (k === m) {
          hits.push(i - m + 1);
          k = pi[k - 1];
        }
      }
      return hits;
    }

    Summary

    • KMP: shrink k on a mismatch, grow it on a match.
    • A trie node holds children and an is_end flag; autocomplete collects words below the prefix node.
    • Positions are bytes in C++, UTF-16 units in Java and TypeScript, code points in Python.

    0 comentários

    Principais comentáriosMais recentes primeiro

    Fazer login · Faça login para deixar um comentário.