Algoritmos e complexidade: questões para praticar com explicações

Questões de múltipla escolha grátis de Algoritmos e complexidade, com dicas e explicações, em três níveis: termos e factos essenciais, aplicar os conceitos, casos e análise.

Exercício gratuitoFácil

Qual classe de complexidade cresce mais rápido para n grande?

Próximo exercício →

O que você pratica

  1. Fáciltermos e factos essenciais
  2. Médiaaplicar os conceitos
  3. Difícilcasos e análise

Aprenda Algoritmos e complexidade do zero

1O que a complexidade mede

Um algoritmo é uma lista finita de passos precisos que resolve um problema, como ordenar uma lista ou achar um nome numa lista telefônica.

Dois algoritmos podem resolver o mesmo problema, mas levar tempos muito diferentes. A complexidade descreve como o trabalho cresce quando a entrada aumenta.

O tamanho da entrada se chama n: o número de itens a ordenar, o comprimento de uma lista, o número de nós de um grafo.

Pense em procurar um nome numa lista telefônica de 1000 páginas. Ler todas as páginas leva até 1000 passos. Abri-la no meio e dividir ao meio a cada vez leva cerca de 10 passos.

A complexidade de tempo conta os passos. A complexidade de espaço conta a memória extra. Ambas são escritas como função de n.

Em geral você olha o pior caso: o maior trabalho entre todas as entradas de tamanho n. Às vezes pede-se o caso médio ou o melhor caso.

Autoavaliação Um algoritmo cujo trabalho cresce como n² leva 1 segundo para n = 1000. Quanto tempo leva, aproximadamente, para n = 2000?
  1. 1 segundo
  2. 2 segundos
  3. 4 segundos
  4. 8 segundos

Resposta: 4 segundos. Dobrar n multiplica n² por 2² = 4, então o tempo vai de cerca de 1 a cerca de 4 segundos. 2 segundos seria a resposta para crescimento linear, e 8 para n³.

2Big O e as classes de crescimento

A notação Big O mantém apenas o que importa para n grande. Você descarta fatores constantes e mantém apenas o termo que cresce mais rápido.

3n² + 5n + 2 ⇒ O(n²)

Para n = 1000 o termo n² é 3 000 000, enquanto 5n é apenas 5000. Os termos menores quase não alteram o total.

Estas classes aparecem repetidamente, do crescimento mais lento ao mais rápido:

  • O(1), constante: ler um elemento de um vetor pelo seu índice.
  • O(log n), logarítmica: a busca binária, que divide o problema ao meio a cada passo.
  • O(n), linear: uma passada por todos os itens, como achar o maior valor.
  • O(n log n): bons algoritmos de ordenação, como o merge sort.
  • O(n²), quadrática: dois laços aninhados sobre os itens, como o bubble sort.
  • O(2ⁿ), exponencial: testar todos os subconjuntos. Torna-se inutilizável rapidamente.
ntlog nnn log nn²2ⁿ

Big O é um limite superior: o trabalho cresce no máximo tão rápido. Ω (Big Omega) é um limite inferior, e Θ (Theta) é um limite justo, tanto superior quanto inferior.

A base de um logaritmo não importa em Big O, porque logaritmos de bases diferentes diferem apenas por um fator constante.

Autoavaliação Qual é o Big O de 4n + 2n² + 100?
  1. O(100)
  2. O(2n²)
  3. O(n)
  4. O(n²)

Resposta: O(n²). Para n grande o termo n² domina, e o fator constante 2 é descartado. O(n) mantém o termo errado, e O(2n²) esquece de descartar a constante.

3Busca, ordenação e recursão

Alguns algoritmos aparecem em quase todo curso. Aprenda as suas complexidades como fatos.

  • A busca linear verifica os itens um a um: O(n). A busca binária precisa de um vetor ordenado e divide o intervalo ao meio a cada passo: O(log n).
  • O bubble sort, o insertion sort e o selection sort comparam e trocam itens em laços aninhados: O(n²). O insertion sort é O(n) em um vetor que já está ordenado.
  • O merge sort divide o vetor em metades, ordena-as e as intercala: O(n log n) em todos os casos, com O(n) de memória extra.
  • O quicksort divide em torno de um pivô: O(n log n) em média, mas O(n²) no pior caso, por exemplo um vetor ordenado com o primeiro elemento como pivô.
  • Nenhuma ordenação que apenas compara itens consegue superar Ω(n log n) no pior caso. O counting sort é mais rápido porque não compara.

Uma função recursiva chama a si mesma com uma entrada menor até chegar a um caso base que ela responde diretamente. Seu tempo de execução é escrito como uma recorrência:

  • T(n) = T(n/2) + O(1) dá O(log n), como a busca binária.
  • T(n) = 2T(n/2) + O(n) dá O(n log n), como o merge sort.
  • T(n) = T(n − 1) + O(n) dá O(n²).
  • T(n) = 2T(n − 1) + O(1) dá O(2ⁿ).

Vale conhecer três ideias de projeto. Dividir e conquistar divide, resolve e combina. O método guloso escolhe a melhor opção local a cada passo. A programação dinâmica guarda as respostas de subproblemas sobrepostos para que sejam calculadas uma só vez.

Autoavaliação Qual é a complexidade de tempo no pior caso do quicksort?
  1. O(log n)
  2. O(n log n)
  3. O(n)
  4. O(n²)

Resposta: O(n²). Com pivôs ruins, cada divisão deixa n − 1 itens de um lado, o que dá O(n²). O(n log n) é o seu caso médio e o pior caso do merge sort.

4O método passo a passo

Para encontrar a complexidade de tempo de um trecho de código:

  1. Decida o que é n: o tamanho da entrada.
  2. Conte quantas vezes cada laço executa. Um laço que soma 1 a cada vez executa cerca de n vezes. Um laço que dobra ou divide ao meio executa cerca de log₂ n vezes.
  3. Laços um dentro do outro se multiplicam. Laços um após o outro se somam.
  4. Para uma função recursiva, escreva a recorrência: quantas chamadas, com que tamanho, mais o trabalho por chamada.
  5. Mantenha o termo que cresce mais rápido e descarte as constantes.
  6. Verifique com um número pequeno, por exemplo n = 8 ou n = 1024.

Para uma questão teórica, primeiro nomeie o algoritmo ou a ideia que ela descreve e depois recorde a sua complexidade e as suas condições (entrada ordenada, pesos não negativos, subproblemas sobrepostos).

5Um exemplo resolvido

Acompanhe cada passo. Tente prever o próximo antes de abri-lo.

Exemplo resolvido

Qual é a complexidade de tempo deste código? for i = 1 to n: (j = 1; while j < n: j = j × 2)

1

Dê nome ao tamanho da entrada

n é o número até o qual os laços executam.

2

Conte o laço externo

i vai de 1 a n em passos de 1, então o laço externo executa n vezes.

3

Conte o laço interno

j assume os valores 1, 2, 4, 8, … e para ao chegar a n. Após k voltas j = 2k, então o laço para depois de cerca de log₂ n voltas.

4

Combine os laços

O laço interno está dentro do externo, então as contagens se multiplicam.

n · log₂ n ⇒ O(n log n)
5

Confira com um número

Para n = 1024 o laço interno executa log₂ 1024 = 10 vezes, então o corpo executa 1024 · 10 = 10 240 vezes. Isso é muito menos que n² = 1 048 576.

Resposta

O(n log n)

6Erros comuns

  • Multiplicar laços que executam um após o outro. n + n = 2n continua sendo O(n).
  • Manter constantes, como em O(2n) ou O(n/2). Ambos são O(n).
  • Contar um laço que dobra como n voltas. Ele executa cerca de log₂ n vezes.
  • Usar busca binária em dados não ordenados, ou em uma lista encadeada em que o meio não pode ser alcançado em um passo.
  • Dar o caso médio do quicksort quando o pior caso é pedido.
  • Pensar que Big O significa “exatamente”. O(n²) é um limite superior; Θ(n²) é o crescimento exato.
Autoavaliação Uma função executa um laço de n iterações e depois, separadamente, outro laço de n iterações. Qual é a sua complexidade de tempo?
  1. O(2n)
  2. O(log n)
  3. O(n)
  4. O(n²)

Resposta: O(n). Laços um após o outro se somam: n + n = 2n, e a constante é descartada, então O(n). O(n²) só estaria certo se um laço estivesse dentro do outro.

7Como são as questões de prova

  • Fácil: termos e fatos-chave. A complexidade da busca binária, do merge sort ou do acesso a um vetor, o significado de O, Ω e Θ, o que é recursão.
  • Médio: aplicação dos conceitos. A complexidade de um trecho de código, uma recorrência para resolver, como o tempo muda quando n dobra, qual algoritmo serve para uma tarefa.
  • Difícil: casos e análise. O teorema mestre, os piores casos do quicksort, guloso versus programação dinâmica e as classes P, NP e NP-completo.

P contém os problemas que podem ser resolvidos em tempo polinomial. NP contém os problemas cujas soluções podem ser verificadas em tempo polinomial. Todo problema de P está em NP; se P = NP ainda é desconhecido.

Aprenda passo a passo no aplicativoAprenda passo a passo no aplicativo

Questões de exemplo

Exemplo 1Fácil

Qual notação descreve um limite superior de crescimento?

  1. AÔmega grande (Big Omega)
  2. BÔmega pequeno (little omega)
  3. CO grande (Big O)
  4. DTheta grande (Big Theta)
Mostrar dicas
  1. "No máximo".
  2. Agora há duas respostas erradas riscadas. Uma das duas que restam está certa.
Mostrar a resposta e a explicação

Porque é esta a resposta

O fornece um limite superior, Ω um limite inferior e Θ um limite justo.

Resposta

C · O grande (Big O)
Exemplo 2Média

Num array ordenado, você procura dois elementos cuja soma seja um alvo movendo um ponteiro de cada extremidade para dentro. Qual é a complexidade de tempo?

  1. AO(n)
  2. BO(n log n)
  3. CO(n²)
  4. DO(log n)
Mostrar dicas
  1. Cada passo move um ponteiro uma posição.
  2. Agora há duas respostas erradas riscadas. Uma das duas que restam está certa.
Mostrar a resposta e a explicação

Porque é esta a resposta

Se a soma for pequena demais, o ponteiro da esquerda vai para a direita; se for grande demais, o da direita vai para a esquerda, então há no máximo n passos.

Resposta

A · O(n)
Exemplo 3Difícil

O algoritmo de Strassen multiplica matrizes usando 7, em vez de 8, multiplicações recursivas de blocos de metade do tamanho. Qual é o seu tempo de execução?

  1. AΘ(n² log n)
  2. BΘ(n2)
  3. CΘ(n³)
  4. DΘ(nlog₂ 7), cerca de n2,81
Mostrar dicas
  1. A recorrência é T(n) = 7T(n/2) + O(n²).
  2. Agora há duas respostas erradas riscadas. Uma das duas que restam está certa.
Mostrar a resposta e a explicação

Porque é esta a resposta

Com a = 7 e b = 2, nlog₂ 7 domina o trabalho O(n²) das adições, o que dá cerca de n2,81.

Resposta

D · Θ(nlog₂ 7), cerca de n2,81

Perguntas e respostas

Algoritmos e complexidade: o que é?

Um algoritmo é uma lista finita de passos precisos que resolve um problema, como ordenar uma lista ou achar um nome numa lista telefônica.

Dois algoritmos podem resolver o mesmo problema, mas levar tempos muito diferentes. A complexidade descreve como o trabalho cresce quando a entrada aumenta.

Algoritmos e complexidade: como aprender passo a passo?
  1. O que a complexidade mede
  2. Big O e as classes de crescimento
  3. Busca, ordenação e recursão
  4. O método passo a passo
  5. Um exemplo resolvido
  6. Erros comuns
  7. Como são as questões de prova
Algoritmos e complexidade: o que se pratica?
  • Fácil: termos e factos essenciais
  • Média: aplicar os conceitos
  • Difícil: casos e análise

Cada questão tem quatro alternativas, e só uma está certa. Travou? Abra primeiro uma dica pequena, e a explicação completa só quando precisar.

Como a prática funciona

  • Cada questão tem quatro alternativas, e só uma está certa.
  • Travou? Abra primeiro uma dica pequena, e a explicação completa só quando precisar.
  • Seu progresso, seus erros e seus exercícios salvos ficam guardados, para você revisar antes da prova.

Temas antes e depois deste

Depois continue com

Disciplinas com este tópico

Mais temas de Informática

Lista de exercícios para imprimir