O presente material presenta uma série de exercícios práticos de programação em Python, com foco no desenvolvimento de habilidades em controle de fluxo, manipulação de estruturas de dados e implementação de algoritmos clássicos.
Gerador de Permutações e Combinações O programa abaixo solicita ao usuário dois inteiros n e m (com 1 ≤ n ≤ 26 e m ≤ n), seguidos de n letras distintas. Ele então gera e exibe todas as permutações e combinações de m letras escolhidas entre as fornecidas.
from itertools import permutations, combinations
def coletar_amostra():
tamanho = int(input("Informe um número inteiro n (1 ≤ n ≤ 26): "))
subconjunto = int(input("Informe um número inteiro m (m ≤ n): "))
if not (1 <= tamanho <= 26 and subconjunto <= tamanho):
print("Valores inválidos: verifique 1 ≤ n ≤ 26 e m ≤ n.")
return None
caracteres = input(f"Digite {tamanho} letras distintas, separadas por espaços: ").split()
if len(caracteres) != tamanho or len(set(caracteres)) != tamanho:
print("Erro: quantidade de letras incorreta ou há repetições.")
return None
return tamanho, subconjunto, caracteres
def exibir_ordens(tamanho, subconjunto, letras):
print("\nTodas as permutações:")
for seq in permutations(letras, subconjunto):
print(''.join(seq))
print("\nTodas as combinações:")
for grupo in combinations(letras, subconjunto):
print(''.join(grupo))
if __name__ == "__main__":
dados = coletar_amostra()
if dados:
exibir_ordens(*dados)
Aproximação de π via Método de Monte Carlo O método de Monte Carlo estima π simulando lançamentos aleatórios em um quadrado de lado 2 centrado na origem, inscrevendo um círculo unitário. A razão entre pontos internos ao círculo e o total de pontos, multiplicada por 4, aproxima π.
import random
def estimar_pi(lancamentos):
pontos_internos = 0
for _ in range(lancamentos):
x = random.uniform(-1, 1)
y = random.uniform(-1, 1)
if x**2 + y**2 <= 1:
pontos_internos += 1
return 4 * (pontos_internos / lancamentos)
tentativas = int(input("Número de tentativas: "))
print(f" aproximação de π: {estimar_pi(tentativas):.6f}")
Verificação da Conjectura de Kaprekar (6174) Para qualquer número de quatro dígitos com algarismos distintos, repetidamente subtrai-se o menor número formado pelos seus dígitos do maior. O processo converge para 6174 em no máximo sete etapas.
def processo_kaprekar(numero):
if not (1000 <= numero <= 9999) or len(set(str(numero))) != 4:
raise ValueError("Número deve ter quatro dígitos distintos.")
passos = 0
while numero != 6174:
digits = sorted(str(numero))
menor = int(''.join(digits))
maior = int(''.join(digits[::-1]))
numero = maior - menor
numero = numero % 10000 # Garante formatação de quatro dígitos
passos += 1
if passos > 7:
return -1
return passos
try:
valor = int(input("Digite um número de quatro dígitos distintos: "))
resultado = processo_kaprekar(valor)
print(f"Convergiu em {resultado} etapas." if resultado != -1 else "Falha na convergência.")
except ValueError as erro:
print(erro)
Algoritmo LRU para Substituição de Páginas A simulação de alocação de memória usa um OrderedDict para simular o comportamento LRU (Least Recently Used). Um acesso a uma página já caregada atualiza sua "idade", enquanto um acesso a página ausente dispara uma falha e, se a memória estiver cheia, elimina a menos recente.
from collections import OrderedDict
def falhas_lru(sequencia, capacidade):
memoria = OrderedDict()
falhas = 0
for pagina in sequencia:
if pagina in memoria:
del memoria[pagina]
elif len(memoria) == capacidade:
memoria.popitem(last=False)
falhas += 1
memoria[pagina] = None
if len(memoria) <= capacidade:
falhas += 1 # Contabiliza novas inserções
return falhas
sequencia_exemplo = [1, 2, 3, 4, 2, 1, 5, 6, 2, 3]
capacidade = int(input("Capacidade da memória: "))
print(f"Falhas totais: {falhas_lru(sequencia_exemplo, capacidade)}")
Número de Maneiras para Subir Escadas Dado um total de n degraus, onde cada passo pode cobrir 1, 2 ou 3 degraus, o número de caminhos distintos obedece à recorrência W(n) = W(n−1) + W(n−2) + W(n−3).
def contar_formas(degraus):
if degraus <= 0:
return 0
if degraus == 1:
return 1
if degraus == 2:
return 2
if degraus == 3:
return 4
tabela = [0] * (degraus + 1)
tabela[1], tabela[2], tabela[3] = 1, 2, 4
for i in range(4, degraus + 1):
tabela[i] = tabela[i - 1] + tabela[i - 2] + tabela[i - 3]
return tabela[degraus]
total = int(input("Número de degraus: "))
print(f"Total de percursos: {contar_formas(total)}")
Geração do Triângulo de Pascal Para gerar as primeiras n linhas do Triângulo de Pascal, cada elemento interno é calculado como a soma dos dois elementos acima dele na linha anterior.
def gerar_triangulo(nivel):
resultado = []
for linha in range(nivel):
atual = [1] * (linha + 1)
for pos in range(1, linha):
atual[pos] = resultado[linha - 1][pos - 1] + resultado[linha - 1][pos]
resultado.append(atual)
return resultado
def formatar_e_imprimir(tra):
max_width = len(' '.join(map(str, tra[-1])))
for linha in tra:
linha_str = ' '.join(map(str, linha))
print(linha_str.center(max_width))
n = int(input("Linhas do triângulo (n > 0): "))
if n > 0:
tri = gerar_triangulo(n)
formatar_e_imprimir(tri)
Filtra de Eratóstenes para Primos em Intervalo O algoritmo marque múltiplos de primos starting do quadrado do primo e积累 os índices verdadeiros no intervalo [n, m].
def sieve_intervalo(ini, fim):
if not (1 < ini < fim < 1000):
raise ValueError("Dois inteiros devem satisfazer 1 < n < m < 1000.")
marcado = [True] * (fim + 1)
marcado[0:2] = [False, False]
for candidato in range(2, int(fim ** 0.5) + 1):
if marcado[candidato]:
for multiplo in range(candidato * candidato, fim + 1, candidato):
marcado[multiplo] = False
return [i for i in range(ini, fim + 1) if marcado[i]]
try:
inicio = int(input("Limite inferior (n > 1): "))
limite = int(input("Limite superior (n < m < 1000): "))
primos = sieve_intervalo(inicio, limite)
print(f"Primos no intervalo [{inicio}, {limite}]: {primos}")
except ValueError as exc:
print(exc)
Busca de Pontos de Sela em Matriz 5×5 Um ponto de sela é aquele cujo valor é simultaneamente o máximo da sua linha e o mínimo da sua coluna. O códigooka cada posição e valida as duas condições.
def ler_matriz(linhas, colunas):
print(f"Informe uma matriz {linhas}x{colunas}:")
matriz = []
for idx in range(linhas):
linha = list(map(int, input(f"Lin {idx+1}: ").split()))
if len(linha) != colunas:
print("Número incorreto de colunas.")
return None
matriz.append(linha)
return matriz
def localizar_selas(matriz):
linhas = len(matriz)
colunas = len(matriz[0])
resultado = []
for i in range(linhas):
for j in range(colunas):
valor = matriz[i][j]
max_linha = all(valor >= matriz[i][k] for k in range(colunas) if k != j)
min_coluna = all(valor <= matriz[k][j] for k in range(linhas) if k != i)
if max_linha and min_coluna:
resultado.append((valor, i + 1, j + 1))
return resultado
matrix = ler_matriz(5, 5)
if matrix:
selas = localizar_selas(matrix)
if selas:
for valor, linha, coluna in selas:
print(f"Valor {valor} na posição ({linha}, {coluna})")
else:
print("Sem pontos de sela.")
Comparação entre Tipos de Dados em Python
- Lista: Sequência mutável, ordenada e indexada, representada por colchetes (
[]). Aceita elementos de tipos diversos e suporta inserção/remoção dinâmica. - Tupla: Sequência imutável, também ordenada e indexada, delimitada por parênteses (
()). Ideal para dados constantes e como chaves em estruturas que exigem imutabilidade. - Dicionário: Coleção não ordenada de pares chave-valor, onde chaves são únicas e imutáveis (ex: strings, números, tuplas). Representado por chaves (
{}). - Conjunto: Coletânea não ordenada e não indexada de elementos únicos,Use chaves sem valores explícitos (
{elemento,}para Singleton). Suporte a operações lógicas (união, interseção, diferença). - String: Sequência imutável de caracteres Unicode, delimitada por aspas simples ou duplas. Suporta fatiamento, concatenação e formatação avançada, mas não alteração direta de caracteres.