Computer Science › Algoritmos e Software

Algoritmos

0 de 32
  1. Memoização, DP de Cima para Baixo

    Memoização pega uma função recursiva já correta e adiciona apenas um cache, verificado no início e preenchido no fim, colapsando o número de chamadas exponencial de Fibonacci ingênuo para O(n) subproblemas distintos calculados, sem eliminar o custo de pilha de chamada.

    Ler →6 seções12 min
  2. Tabulação, DP de Baixo para Cima

    Tabulação resolve os mesmos subproblemas que memoização, no mesmo tempo assintótico, preenchendo uma tabela iterativamente do menor caso base para cima em vez de recursar para baixo com um cache, eliminando o custo de pilha de chamada por completo.

    Ler →6 seções11 min
  3. DP: Subsequência Comum Mais Longa

    LCS é o primeiro exemplo de DP com subproblemas indexados por dois parâmetros independentes; sua recorrência ramifica em se os últimos caracteres de dois prefixos combinam, e uma tabela 2D preenchida por essa regra também permite recuperar a subsequência real por rastreamento reverso.

    Ler →6 seções9 min
  4. DP: Mochila 0/1

    Mochila 0/1 é o contraponto honesto ao sucesso de guloso em seleção de atividades, um contraexemplo concreto mostra a estratégia de melhor razão valor/peso travando na escolha errada, enquanto a recorrência de DP K(i,c) = max(pular, pegar) encontra o ótimo verdadeiro.

    Ler →6 seções11 min
  5. DP: Subsequência Crescente Mais Longa

    LIS admite tanto uma DP direta O(n²) (L(i) = 1 + max sobre L(j) anteriores de valor menor) quanto uma abordagem O(n log n) mantendo o menor final possível por comprimento, atualizado por busca binária, uma aplicação direta da busca binária generalizada.

    Ler →6 seções12 min
  6. Fluxo em Redes e o Problema do Fluxo Máximo

    Uma rede de fluxo é um grafo direcionado com capacidade em toda aresta, uma fonte e um sumidouro; um fluxo válido respeita capacidade e conservação em todo vértice intermediário, e o fluxo máximo pergunta qual atribuição válida maximiza o valor total.

    Ler →6 seções11 min
  7. O Método de Ford-Fulkerson e Caminhos de Aumento

    O grafo residual guarda, para toda aresta, a capacidade direta não usada mais uma aresta reversa de "desfazer"; o método repete encontrar um caminho de aumento e empurrar fluxo pelo gargalo até que nenhum caminho reste.

    Ler →6 seções11 min
  8. O Teorema do Fluxo Máximo e Corte Mínimo

    O valor de qualquer fluxo válido nunca excede a capacidade de nenhum corte s-t (dualidade fraca), e o valor do fluxo máximo é sempre exatamente igual à capacidade do corte mínimo, provado construtivamente a partir do ponto de término de Ford-Fulkerson.

    Ler →6 seções11 min
  9. Edmonds-Karp e Análise de Complexidade

    Escolher sempre o caminho de aumento com menos arestas, via BFS no grafo residual, limita o número de iterações a O(V·E) independente das capacidades, contra uma escolha arbitrária de caminho cujo número de iterações pode depender diretamente do valor numérico das capacidades.

    Ler →6 seções11 min
  10. Travessia de Grafo: Busca em Largura

    BFS explora um grafo nível por nível usando uma fila, e a disciplina FIFO da fila é exatamente o que garante que a primeira descoberta de todo vértice aconteça via um caminho mais curto em número de arestas, tudo em tempo O(V + E).

    Ler →6 seções13 min
  11. Travessia de Grafo: Busca em Profundidade

    DFS mergulha completamente na subárvore alcançável de um vizinho antes de tentar o próximo, uma disciplina LIFO natural via pilha ou recursão; produz uma árvore comprida e sinuosa, com timestamps de descoberta e término aninhados que o próximo tópico usa diretamente.

    Ler →6 seções13 min
  12. Detecção de Ciclo e Ordenação Topológica

    Uma aresta de retorno em DFS direcionado (para um ancestral ainda na pilha) existe se e somente se o grafo tem um ciclo; quando não há ciclo, os mesmos tempos de término de DFS, lidos em ordem decrescente, produzem uma ordenação topológica válida.

    Ler →6 seções12 min
  13. Caminhos Mais Curtos Ponderados

    Uma vez que arestas carregam pesos, "caminho mais curto" significa peso total mínimo, não menos arestas; toda solução se constrói sobre relaxamento, mantendo uma distância tentativa que nunca subestima a verdade, com a escolha de quais arestas relaxar e em que ordem distinguindo os algoritmos seguintes.

    Ler →6 seções12 min
  14. O Algoritmo de Dijkstra

    Dijkstra finaliza repetidamente o vértice não finalizado de menor distância tentativa usando um heap binário para extract-min O(log V), dando O((V+E) log V) no total; a prova de correção depende inteiramente de pesos de aresta não negativos.

    Ler →6 seções14 min
  15. O Algoritmo de Bellman-Ford

    Bellman-Ford abandona a estratégia gulosa e relaxa toda aresta V−1 vezes, garantindo distâncias corretas mesmo com pesos negativos; uma rodada V extra, ainda encontrando melhoria, prova um ciclo de peso negativo alcançável a partir da fonte.

    Ler →6 seções12 min
  16. Caminhos Mais Curtos em um DAG

    Saber de antemão que um grafo é um DAG permite processar vértices em ordem topológica e relaxar cada aresta de saída exatamente uma vez, dando O(V + E), mais rápido que Dijkstra e Bellman-Ford, e tolerando arestas negativas já que não há ciclo negativo possível.

    Ler →6 seções12 min
  17. Componentes Conexos via BFS

    \"Existe caminho entre eles\" é uma relação de equivalência que particiona os vértices de um grafo em componentes conexos; rodar BFS de todo vértice ainda não visitado descobre cada componente exatamente uma vez, tudo ainda em O(V + E).

    Ler →6 seções11 min
  18. O Paradigma Guloso

    Um algoritmo guloso sempre toma a escolha localmente melhor e nunca reconsidera; o contraexemplo de troco de moedas com {1, 3, 4} mostra que isso pode produzir uma resposta válida mas comprovadamente não ótima, então correção de um algoritmo guloso é uma propriedade do problema específico, não uma garantia universal.

    Ler →6 seções13 min
  19. O Problema da Árvore Geradora Mínima

    A propriedade de corte garante que, entre as arestas cruzando qualquer partição de vértices, a mais barata pertence a alguma MST; isso licencia uma estratégia gulosa com garantia de correção real, o modelo que tanto Kruskal quanto Prim instanciam.

    Ler →6 seções17 min
  20. O Algoritmo de Kruskal

    Kruskal ordena todas as arestas por peso e as processa em sequência, aceitando cada uma a menos que union-find diga que seus extremos já estão conectados; a correção vem da propriedade de corte, e o tempo de execução O(E log E) é dominado pela ordenação, não pelas operações de union-find.

    Ler →6 seções13 min
  21. O Algoritmo de Prim

    Prim cresce uma única árvore a partir de um vértice, extraindo repetidamente a aresta mais barata cruzando o corte árvore-versus-resto via um heap binário; compartilha o esqueleto de Dijkstra mas compara pesos de aresta crus, não distâncias de caminho acumuladas.

    Ler →6 seções16 min
  22. Provando Otimalidade Gulosa, Seleção de Atividades

    A regra gulosa de sempre selecionar a atividade compatível que termina mais cedo é comprovadamente ótima para seleção de atividades; o argumento de troca mostra que qualquer solução ótima pode ser transformada para concordar com a escolha gulosa sem perder tamanho, e a indução estende isso a toda a sequência.

    Ler →6 seções15 min
  23. O Paradigma Dividir para Conquistar

    Dividir para conquistar é recursão disciplinada de uma forma específica, divida o problema em instâncias fracionalmente menores, conquiste cada uma recursivamente, combine as respostas; a fração de redução, não o simples fato de encolher, é o que produz níveis logarítmicos.

    Ler →6 seções14 min
  24. Busca Além da Busca Binária

    A garantia real por trás de busca binária não é "o array está ordenado" mas que uma comparação basta para descartar metade dos candidatos; um array ordenado rotacionado preserva exatamente essa propriedade e ainda pode ser buscado em O(log n).

    Ler →6 seções11 min
  25. Resolvendo Recorrências

    A árvore de recursão transforma uma recorrência auto-referente em uma figura, contando níveis e o trabalho por nível para chegar a T(n) = Θ(n log n) para merge sort e Θ(log n) para busca binária, sem precisar do Teorema Mestre completo.

    Ler →6 seções15 min
  26. Merge Sort Revisitado

    Merge sort como a ilustração completa canônica de dividir para conquistar, com sua recorrência T(n) = 2T(n/2) + O(n) resolvida por completo, sua estabilidade provada a partir da comparação <=, e seu custo de espaço Θ(n) derivado da mecânica do próprio merge.

    Ler →6 seções13 min
  27. Particionamento no Quicksort

    Quicksort faz o trabalho pesado durante dividir, não combinar, particionando o array em torno de um pivô escolhido usando apenas trocas in-place; os esquemas de Lomuto e Hoare fazem isso de formas diferentes, com garantias de retorno diferentes.

    Ler →6 seções13 min
  28. Caso Médio e Randomização no Quicksort

    Um pivô fixo (primeiro ou último elemento) degrada quicksort para O(n²) em entradas comuns como arrays já ordenados; escolher o pivô uniformemente ao acaso quebra o vínculo entre entrada e sequência de escolhas ruins, tornando O(n log n) o esperado em qualquer entrada.

    Ler →6 seções14 min
  29. O Limite Inferior de Ordenação por Comparação

    Modelar qualquer ordenação por comparação como uma árvore de decisão binária mostra que ela precisa de pelo menos n! folhas, forçando altura Ω(n log n); combinado com o limite superior O(n log n) do merge sort, isso prova que merge sort é assintoticamente ótimo entre ordenações por comparação.

    Ler →6 seções15 min
  30. Quicksort vs. Merge Sort

    As duas ordenações O(n log n) fazem trocas opostas, quicksort troca uma garantia de pior caso por particionamento in-place e melhor localidade de cache; merge sort troca espaço O(n) e sobrecarga de merge por O(n log n) incondicional e estabilidade.

    Ler →6 seções12 min
  31. Escolhendo um Paradigma: Um Guia de Decisão

    Dividir para conquistar, guloso, e programação dinâmica se distinguem por uma pergunta estrutural, subproblemas independentes, uma escolha localmente melhor irrevogável e comprovadamente segura, ou subproblemas sobrepostos, reconhecer qual sinal um novo problema exibe é a habilidade transferível que esta disciplina construiu.

    Ler →6 seções12 min

Algoritmos

Part of the Computer Science curriculum.

Sort
1

O Paradigma de Programação Dinâmica

Um problema se qualifica para programação dinâmica exatamente quando tem subproblemas sobrepostos (a mesma chamada recursiva se repete) E subestrutura ótima (a resposta ótima ao todo se constrói das respostas ótimas às partes); nenhuma das duas sozinha basta.

2

Memoização, DP de Cima para Baixo

Memoização pega uma função recursiva já correta e adiciona apenas um cache, verificado no início e preenchido no fim, colapsando o número de chamadas exponencial de Fibonacci ingênuo para O(n) subproblemas distintos calculados, sem eliminar o custo de pilha de chamada.

3

Tabulação, DP de Baixo para Cima

Tabulação resolve os mesmos subproblemas que memoização, no mesmo tempo assintótico, preenchendo uma tabela iterativamente do menor caso base para cima em vez de recursar para baixo com um cache, eliminando o custo de pilha de chamada por completo.

4

DP: Subsequência Comum Mais Longa

LCS é o primeiro exemplo de DP com subproblemas indexados por dois parâmetros independentes; sua recorrência ramifica em se os últimos caracteres de dois prefixos combinam, e uma tabela 2D preenchida por essa regra também permite recuperar a subsequência real por rastreamento reverso.

5

DP: Mochila 0/1

Mochila 0/1 é o contraponto honesto ao sucesso de guloso em seleção de atividades, um contraexemplo concreto mostra a estratégia de melhor razão valor/peso travando na escolha errada, enquanto a recorrência de DP K(i,c) = max(pular, pegar) encontra o ótimo verdadeiro.

6

DP: Subsequência Crescente Mais Longa

LIS admite tanto uma DP direta O(n²) (L(i) = 1 + max sobre L(j) anteriores de valor menor) quanto uma abordagem O(n log n) mantendo o menor final possível por comprimento, atualizado por busca binária, uma aplicação direta da busca binária generalizada.

7

Fluxo em Redes e o Problema do Fluxo Máximo

Uma rede de fluxo é um grafo direcionado com capacidade em toda aresta, uma fonte e um sumidouro; um fluxo válido respeita capacidade e conservação em todo vértice intermediário, e o fluxo máximo pergunta qual atribuição válida maximiza o valor total.

8

O Método de Ford-Fulkerson e Caminhos de Aumento

O grafo residual guarda, para toda aresta, a capacidade direta não usada mais uma aresta reversa de "desfazer"; o método repete encontrar um caminho de aumento e empurrar fluxo pelo gargalo até que nenhum caminho reste.

9

O Teorema do Fluxo Máximo e Corte Mínimo

O valor de qualquer fluxo válido nunca excede a capacidade de nenhum corte s-t (dualidade fraca), e o valor do fluxo máximo é sempre exatamente igual à capacidade do corte mínimo, provado construtivamente a partir do ponto de término de Ford-Fulkerson.

10

Edmonds-Karp e Análise de Complexidade

Escolher sempre o caminho de aumento com menos arestas, via BFS no grafo residual, limita o número de iterações a O(V·E) independente das capacidades, contra uma escolha arbitrária de caminho cujo número de iterações pode depender diretamente do valor numérico das capacidades.

11

Travessia de Grafo: Busca em Largura

BFS explora um grafo nível por nível usando uma fila, e a disciplina FIFO da fila é exatamente o que garante que a primeira descoberta de todo vértice aconteça via um caminho mais curto em número de arestas, tudo em tempo O(V + E).

12

Travessia de Grafo: Busca em Profundidade

DFS mergulha completamente na subárvore alcançável de um vizinho antes de tentar o próximo, uma disciplina LIFO natural via pilha ou recursão; produz uma árvore comprida e sinuosa, com timestamps de descoberta e término aninhados que o próximo tópico usa diretamente.

13

Detecção de Ciclo e Ordenação Topológica

Uma aresta de retorno em DFS direcionado (para um ancestral ainda na pilha) existe se e somente se o grafo tem um ciclo; quando não há ciclo, os mesmos tempos de término de DFS, lidos em ordem decrescente, produzem uma ordenação topológica válida.

14

Caminhos Mais Curtos Ponderados

Uma vez que arestas carregam pesos, "caminho mais curto" significa peso total mínimo, não menos arestas; toda solução se constrói sobre relaxamento, mantendo uma distância tentativa que nunca subestima a verdade, com a escolha de quais arestas relaxar e em que ordem distinguindo os algoritmos seguintes.

15

O Algoritmo de Dijkstra

Dijkstra finaliza repetidamente o vértice não finalizado de menor distância tentativa usando um heap binário para extract-min O(log V), dando O((V+E) log V) no total; a prova de correção depende inteiramente de pesos de aresta não negativos.

16

O Algoritmo de Bellman-Ford

Bellman-Ford abandona a estratégia gulosa e relaxa toda aresta V−1 vezes, garantindo distâncias corretas mesmo com pesos negativos; uma rodada V extra, ainda encontrando melhoria, prova um ciclo de peso negativo alcançável a partir da fonte.

17

Caminhos Mais Curtos em um DAG

Saber de antemão que um grafo é um DAG permite processar vértices em ordem topológica e relaxar cada aresta de saída exatamente uma vez, dando O(V + E), mais rápido que Dijkstra e Bellman-Ford, e tolerando arestas negativas já que não há ciclo negativo possível.

18

Componentes Conexos via BFS

\"Existe caminho entre eles\" é uma relação de equivalência que particiona os vértices de um grafo em componentes conexos; rodar BFS de todo vértice ainda não visitado descobre cada componente exatamente uma vez, tudo ainda em O(V + E).

19

O Paradigma Guloso

Um algoritmo guloso sempre toma a escolha localmente melhor e nunca reconsidera; o contraexemplo de troco de moedas com {1, 3, 4} mostra que isso pode produzir uma resposta válida mas comprovadamente não ótima, então correção de um algoritmo guloso é uma propriedade do problema específico, não uma garantia universal.

20

O Problema da Árvore Geradora Mínima

A propriedade de corte garante que, entre as arestas cruzando qualquer partição de vértices, a mais barata pertence a alguma MST; isso licencia uma estratégia gulosa com garantia de correção real, o modelo que tanto Kruskal quanto Prim instanciam.

21

O Algoritmo de Kruskal

Kruskal ordena todas as arestas por peso e as processa em sequência, aceitando cada uma a menos que union-find diga que seus extremos já estão conectados; a correção vem da propriedade de corte, e o tempo de execução O(E log E) é dominado pela ordenação, não pelas operações de union-find.

22

O Algoritmo de Prim

Prim cresce uma única árvore a partir de um vértice, extraindo repetidamente a aresta mais barata cruzando o corte árvore-versus-resto via um heap binário; compartilha o esqueleto de Dijkstra mas compara pesos de aresta crus, não distâncias de caminho acumuladas.

23

Provando Otimalidade Gulosa, Seleção de Atividades

A regra gulosa de sempre selecionar a atividade compatível que termina mais cedo é comprovadamente ótima para seleção de atividades; o argumento de troca mostra que qualquer solução ótima pode ser transformada para concordar com a escolha gulosa sem perder tamanho, e a indução estende isso a toda a sequência.

24

O Paradigma Dividir para Conquistar

Dividir para conquistar é recursão disciplinada de uma forma específica, divida o problema em instâncias fracionalmente menores, conquiste cada uma recursivamente, combine as respostas; a fração de redução, não o simples fato de encolher, é o que produz níveis logarítmicos.

25

Busca Além da Busca Binária

A garantia real por trás de busca binária não é "o array está ordenado" mas que uma comparação basta para descartar metade dos candidatos; um array ordenado rotacionado preserva exatamente essa propriedade e ainda pode ser buscado em O(log n).

26

Resolvendo Recorrências

A árvore de recursão transforma uma recorrência auto-referente em uma figura, contando níveis e o trabalho por nível para chegar a T(n) = Θ(n log n) para merge sort e Θ(log n) para busca binária, sem precisar do Teorema Mestre completo.

27

Merge Sort Revisitado

Merge sort como a ilustração completa canônica de dividir para conquistar, com sua recorrência T(n) = 2T(n/2) + O(n) resolvida por completo, sua estabilidade provada a partir da comparação <=, e seu custo de espaço Θ(n) derivado da mecânica do próprio merge.

28

Particionamento no Quicksort

Quicksort faz o trabalho pesado durante dividir, não combinar, particionando o array em torno de um pivô escolhido usando apenas trocas in-place; os esquemas de Lomuto e Hoare fazem isso de formas diferentes, com garantias de retorno diferentes.

29

Caso Médio e Randomização no Quicksort

Um pivô fixo (primeiro ou último elemento) degrada quicksort para O(n²) em entradas comuns como arrays já ordenados; escolher o pivô uniformemente ao acaso quebra o vínculo entre entrada e sequência de escolhas ruins, tornando O(n log n) o esperado em qualquer entrada.

30

O Limite Inferior de Ordenação por Comparação

Modelar qualquer ordenação por comparação como uma árvore de decisão binária mostra que ela precisa de pelo menos n! folhas, forçando altura Ω(n log n); combinado com o limite superior O(n log n) do merge sort, isso prova que merge sort é assintoticamente ótimo entre ordenações por comparação.

31

Quicksort vs. Merge Sort

As duas ordenações O(n log n) fazem trocas opostas, quicksort troca uma garantia de pior caso por particionamento in-place e melhor localidade de cache; merge sort troca espaço O(n) e sobrecarga de merge por O(n log n) incondicional e estabilidade.

32

Escolhendo um Paradigma: Um Guia de Decisão

Dividir para conquistar, guloso, e programação dinâmica se distinguem por uma pergunta estrutural, subproblemas independentes, uma escolha localmente melhor irrevogável e comprovadamente segura, ou subproblemas sobrepostos, reconhecer qual sinal um novo problema exibe é a habilidade transferível que esta disciplina construiu.