Utilizando Python para Algoritmos Combinatórios, Numéricos e de Estrutura de Dados

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.

Tags: permutação combinação Monte Carlo Kaprekar lru

Publicado em 8-18 02:55