Exercícios de Exame

Limpar todos os resolvidos?

Condições e ciclos

Par ou ímpar decide a operaçãoCódigo

PE1, 2020/21

Escreve um programa em Python que lê três inteiros n1, n2 e n3 dados pelo utilizador. Se n1 for ímpar, o programa escreve o produto de n2 e n3. Se n1 for par, escreve a subtração entre n2 e n3.

Python
n1 = int(input("n1? "))
n2 = int(input("n2? "))
n3 = int(input("n3? "))
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Ímpar dá produto
    Entrada
    3
    4
    5
    Esperado:
    20
  2. Par dá subtração
    Entrada
    2
    4
    5
    Esperado:
    -1

Solução
n1 = int(input("n1? "))
n2 = int(input("n2? "))
n3 = int(input("n3? "))

if n1 % 2 != 0:
    print(n2 * n3)
else:
    print(n2 - n3)

O resto da divisão por 2 distingue par de ímpar: n1 % 2 != 0 é verdadeiro só quando n1 é ímpar. Cada ramo escreve a expressão pedida.

Voltar à explicação
Persistência multiplicativaCódigo

PE1, 2020/21

A persistência multiplicativa de um inteiro positivo é o número de vezes que os seus dígitos podem ser multiplicados até o número ficar com um só dígito. Por exemplo, a persistência de 39 é 3, porque 39 → 3·9 = 27 → 2·7 = 14 → 1·4 = 4. Escreve um programa em Python que, dado um número num lido do utilizador, escreve a sua persistência multiplicativa.

Python
num = int(input("num? "))
count = 0
print(count)
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Entrada
    39
    Esperado:
    3
  2. Um dígito
    Entrada
    4
    Esperado:
    0
  3. Quatro passos
    Entrada
    77
    Esperado:
    4

Solução
num = int(input("num? "))

count = 0
while num > 9:
    aux = 1
    while num != 0:
        aux = (num % 10) * aux
        num = num // 10
    num = aux
    count += 1

print(count)

O ciclo exterior conta um passo por multiplicação. O ciclo interior calcula o produto dos dígitos: num % 10 dá o último dígito e num // 10 o remove. O ciclo termina quando resta um só dígito (num <= 9).

Voltar à explicação
Inverter um inteiro sem usar stringsCódigo

PE1, 2019/20

Escreve um programa em Python que, dado um inteiro num lido do utilizador, calcula o seu reverse (o número com os dígitos por ordem inversa) e o escreve. Não podes converter o número numa string nem manipular strings. Por exemplo, para num = 766 a saída é 667 e para num = 45654 a saída é 45654.

Python
num = int(input("num? "))
rev = 0
print(rev)
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Três dígitos
    Entrada
    766
    Esperado:
    667
  2. Palíndromo
    Entrada
    45654
    Esperado:
    45654
  3. Zero
    Entrada
    0
    Esperado:
    0

Solução
num = int(input("num? "))

tmp = num
rev = 0
while tmp > 0:
    d = tmp % 10
    rev = rev * 10 + d
    tmp = tmp // 10

print(rev)

A cada passo, tmp % 10 extrai o último dígito e rev = rev * 10 + d acrescenta esse dígito à direita do número que está a construir. Para num = 0 o ciclo não corre e a saída é 0.

Voltar à explicação
Converter quaternário para decimalCódigo

PE1, 2019/20

Um número quaternário (base 4) usa apenas os dígitos 0, 1, 2 e 3. Escreve um programa em Python que converte um número quaternário quat (base 4), lido do utilizador, no número decimal (base 10) correspondente. Por exemplo, para quat = 123 a saída é 27 e para quat = 112233 a saída é 1455.

Python
quat = int(input("Quaternary number = "))
dec = 0
print(dec)
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo 123
    Entrada
    123
    Esperado:
    27
  2. Exemplo 11
    Entrada
    11
    Esperado:
    5
  3. Seis dígitos
    Entrada
    112233
    Esperado:
    1455

Solução
quat = int(input("Quaternary number = "))

dec = 0
power = 0

while quat:
    last = quat % 10
    dec += last * 4 ** power
    quat //= 10
    power += 1

print(dec)

Cada dígito last vale last * 4^power, com a posição power a começar em 0. quat % 10 dá o dígito menos significativo e quat //= 10 avança para o seguinte.

Voltar à explicação

Funções

Verificar número de ArmstrongCódigo

PE2, 2020/21

Escreve uma função em Python is_armstrong(n) que verifica se um número n de três dígitos é um número de Armstrong. Num número de Armstrong de três dígitos, a soma dos cubos de cada dígito é igual ao próprio número. A função devolve True ou False.

Python
def is_armstrong(n):
    return False
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. 153 é Armstrong
    Código do teste
    print(is_armstrong(153))
    Esperado:
    True
  2. 370 é Armstrong
    Código do teste
    print(is_armstrong(370))
    Esperado:
    True
  3. 123 não é Armstrong
    Código do teste
    print(is_armstrong(123))
    Esperado:
    False

Solução
def is_armstrong(n):
    soma = 0
    aux = n
    while aux > 0:
        digit = aux % 10
        soma += digit ** 3
        aux //= 10
    return soma == n

Percorrem-se os dígitos de n com aux % 10 e aux //= 10, acumulando o cubo de cada um em soma. No fim, compara-se a soma com o número original. Para 153: 1 + 125 + 27 = 153.

Voltar à explicação
Média móvel com vizinhança ímparCódigo

PE2, 2020/21

Escreve uma função em Python moving_average(alist, n) que, dada uma lista alist de inteiros e um inteiro ímpar n (a amplitude da vizinhança), devolve uma lista com as médias da vizinhança de cada número, arredondadas a duas casas decimais. Cada vizinhança tem exatamente n elementos. Se alist tiver comprimento menor que 3 ou se n < 3, o resultado é a lista vazia. Por exemplo, moving_average([1, 2, 3, 4, 5], 3) devolve [2.0, 3.0, 4.0].

Python
def moving_average(alist, n):
    return []
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Código do teste
    print(moving_average([1, 2, 3, 4, 5], 3))
    Esperado:
    [2.0, 3.0, 4.0]
  2. Lista demasiado curta
    Código do teste
    print(moving_average([1, 2], 3))
    Esperado:
    []
  3. Vizinhança total
    Código do teste
    print(moving_average([1, 2, 3, 4, 5], 5))
    Esperado:
    [3.0]

Solução
def moving_average(alist, n):
    if len(alist) < 3 or n < 3:
        return []
    avgs = []
    for i in range(n // 2, len(alist) - n // 2):
        left = alist[i - n // 2:i]
        right = alist[i + 1:i + n // 2 + 1]
        neighbors = left + right
        avgs.append(round(sum(neighbors) / len(neighbors), 2))
    return avgs

Só os índices com n // 2 elementos de cada lado têm uma vizinhança completa, por isso o ciclo começa em n // 2 e termina antes de len(alist) - n // 2. A média usa os n - 1 vizinhos (o elemento central não entra), como no exemplo: (1+3)/2 = 2.0.

Voltar à explicação
Dígitos por ordem decrescenteCódigo

PE2, 2019/20

Escreve uma função em Python order_digits(n) que, dado um inteiro n maior ou igual a zero, devolve um tuplo com os dígitos do número por ordem decrescente. Por exemplo, se n = 9013322 o resultado é o tuplo (9, 3, 3, 2, 2, 1, 0).

Python
def order_digits(n):
    return ()
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Código do teste
    print(order_digits(9013322))
    Esperado:
    (9, 3, 3, 2, 2, 1, 0)
  2. Zero
    Código do teste
    print(order_digits(0))
    Esperado:
    (0,)
  3. Dígito repetido
    Código do teste
    print(order_digits(500))
    Esperado:
    (5, 0, 0)

Solução
def order_digits(n):
    if n == 0:
        return (0,)
    result = ()
    for i in range(9, -1, -1):
        aux = n
        while aux > 0:
            if aux % 10 == i:
                result += (i,)
            aux //= 10
    return result

Para cada dígito possível de 9 até 0, percorre-se o número e acrescenta-se esse dígito ao tuplo uma vez por cada ocorrência. O caso n == 0 é tratado à parte porque o ciclo while nunca correria.

Voltar à explicação

Strings

Trocar maiúsculas e minúsculasCódigo

PE3, 2020/21

Escreve uma função em Python swap_case(astr) que, dada uma string astr, devolve outra string com todas as letras minúsculas convertidas em maiúsculas e vice-versa. Por exemplo, swap_case("aBcD") devolve "AbCd".

Python
def swap_case(astr):
    return astr
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Código do teste
    print(swap_case('aBcD'))
    Esperado:
    AbCd
  2. Símbolos não mudam
    Código do teste
    print(swap_case('Hello!'))
    Esperado:
    hELLO!

Solução
def swap_case(astr):
    result = ""
    for letter in astr:
        if letter.isupper():
            result += letter.lower()
        else:
            result += letter.upper()
    return result

Percorre-se a string letra a letra e constrói-se o resultado por concatenação, trocando a capitalização de cada letra. Caracteres que não são letras (como !) não são maiúscula nem minúscula e passam para o outro ramo, que os mantém inalterados.

Voltar à explicação
Contar padrões de subcadeiasCódigo

PE2, 2019/20

Escreve uma função em Python subpatterns(astring) que recebe uma string astring e calcula quantas das suas subcadeias seguem um certo padrão. Uma subcadeia é um padrão quando o número de vezes que cresce é igual ao número de vezes que encolhe: num passo, a subcadeia cresce se o caráter for maior que o anterior e encolhe se for menor. Por exemplo, subpatterns("aghljcb") devolve a string "The string 'aghljcb' contains 3 substring patterns.".

Python
def subpatterns(astring):
    return ""
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Código do teste
    print(subpatterns("aghljcb"))
    Esperado:
    The string 'aghljcb' contains 3 substring patterns.
  2. Sem padrões
    Código do teste
    print(subpatterns("ab"))
    Esperado:
    The string 'ab' contains 0 substring patterns.

Solução
def is_pattern(astring):
    net = 0
    for i in range(len(astring) - 1):
        if astring[i + 1] > astring[i]:
            net += 1
        if astring[i + 1] < astring[i]:
            net -= 1
    return net == 0

def subpatterns(astring):
    counter = 0
    for step in range(2, len(astring) + 1):
        for char_index in range(0, len(astring) - step + 1):
            sub_str = astring[char_index:char_index + step]
            if is_pattern(sub_str):
                counter += 1
    return "The string '{0}' contains {1} substring patterns.".format(
        astring, counter)

Uma subcadeia é padrão quando o saldo entre crescimentos (+1) e encolhecimentos (-1) é zero. Experimentam-se todas as subcadeias de comprimento pelo menos 2 e conta-se quantas têm saldo zero.

Voltar à explicação

Dicionários e conjuntos

Valores únicos de uma lista de dicionáriosCódigo

PE3, 2020/21

Escreve uma função em Python unique_values(alist) que, dada uma lista de dicionários alist, devolve um conjunto com os valores de todos os dicionários. Por exemplo, unique_values([{"a": 1, "b": 2}, {"b": 2, "c": 3}]) devolve {1, 2, 3}.

Python
def unique_values(alist):
    return set()
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Código do teste
    print(unique_values([{'a': 1, 'b': 2}, {'b': 2, 'c': 3}]))
    Esperado:
    {1, 2, 3}
  2. Lista vazia
    Código do teste
    print(unique_values([]))
    Esperado:
    set()

Solução
def unique_values(alist):
    uniqs = set()
    for d in alist:
        for v in d.values():
            uniqs.add(v)
    return uniqs

Percorrem-se os valores de cada dicionário com d.values() e juntam-se todos a um conjunto, que elimina duplicados automaticamente.

Voltar à explicação
Somar dicionáriosCódigo

PE4, 2020/21

Escreve uma função em Python sum_dicts(lst) que recebe uma lista lst de dicionários, cada um com um conjunto de chaves e valores inteiros, e devolve um único dicionário com todas as chaves presentes. Os valores associados à mesma chave são somados. Por exemplo, sum_dicts([{"a": 5, "b": 3}, {"a": 1, "c": 0}]) devolve {"a": 6, "b": 3, "c": 0}.

Python
def sum_dicts(lst):
    return {}
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Código do teste
    print(sum_dicts([{'a': 5, 'b': 3}, {'a': 1, 'c': 0}]))
    Esperado:
    {'a': 6, 'b': 3, 'c': 0}
  2. Chave só num dicionário
    Código do teste
    print(sum_dicts([{'x': 2}, {'y': 4}]))
    Esperado:
    {'x': 2, 'y': 4}

Solução
def sum_dicts(lst):
    result = {}
    for d in lst:
        for k, v in d.items():
            result[k] = result.get(k, 0) + v
    return result

Para cada par chave-valor, result.get(k, 0) devolve o valor acumulado ou 0 se a chave ainda não existe, e o valor novo é somado. Assim todas as chaves ficam no dicionário final.

Voltar à explicação
Processar comandos sobre conjuntosCódigo

PE3, 2019/20

Escreve uma função em Python process(commands) que recebe uma lista commands a processar sobre conjuntos, pela ordem dada. Por exemplo, [{1, 3, 4}, "|", {2, 5}] deve ser convertido em {1, 2, 3, 4, 5}. As operações binárias disponíveis são "|" (união), "&" (interseção), "-" (diferença) e "x" (produto cartesiano, que devolve pares).

Python
def process(commands):
    return commands[0]
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. União
    Código do teste
    print(process([{1, 3, 4}, '|', {2, 5}]))
    Esperado:
    {1, 2, 3, 4, 5}
  2. Diferença
    Código do teste
    print(process([{1, 3, 4}, '-', {3}]))
    Esperado:
    {1, 4}
  3. Interseção
    Código do teste
    print(process([{1, 2}, '&', {2, 3}]))
    Esperado:
    {2}

Solução
def process(commands):
    s = commands[0]
    for op, t in zip(commands[1::2], commands[2::2]):
        if op == '|':
            s = s | t
        if op == '&':
            s = s & t
        if op == '-':
            s = s - t
        if op == 'x':
            r = set()
            for i in s:
                for j in t:
                    r.add((i, j))
            s = r
    return s

A lista alterna conjunto, operador, conjunto. commands[1::2] são os operadores e commands[2::2] os operandos seguintes; o zip emparelha-os e cada operador é aplicado ao acumulador s. O produto cartesiano constrói explicitamente o conjunto de pares.

Voltar à explicação

Recursão

Contar elementos numa lista aninhadaCódigo

PE3, 2020/21

Escreve uma função em Python rec_count(alist) que calcula a frequência de cada elemento da lista aninhada alist (uma lista que pode conter listas, que por sua vez podem conter outras listas, e assim sucessivamente) e a devolve na forma de um dicionário. Por exemplo, rec_count([1, [2, [1, 2]], 3]) devolve {1: 2, 2: 2, 3: 1}.

Python
def rec_count(alist):
    return {}
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Código do teste
    print(rec_count([1, [2, [1, 2]], 3]))
    Esperado:
    {1: 2, 2: 2, 3: 1}
  2. Lista vazia
    Código do teste
    print(rec_count([]))
    Esperado:
    {}
  3. Repetidos em níveis diferentes
    Código do teste
    print(rec_count([5, [5]]))
    Esperado:
    {5: 2}

Solução
def rec_count(alist):
    result = {}
    for el in alist:
        if type(el) != list:
            d = {el: 1}
        else:
            d = rec_count(el)
        for k, v in d.items():
            result[k] = result.get(k, 0) + v
    return result

Se o elemento não é uma lista, conta-se como uma ocorrência ({el: 1}); se for, conta-se recursivamente a sublista. Depois de cada chamada recursiva, os pares do dicionário devolvido são somados ao acumulador result.

Voltar à explicação
Contar dígitos recursivamenteCódigo

PE3, 2019/20

Escreve uma função em Python count_digits(n) que calcula a frequência de cada dígito do número n, com n > 0, e a devolve na forma de um dicionário. Não podes usar ciclos nem variáveis globais. Por exemplo, count_digits(12321) devolve {1: 2, 2: 2, 3: 1}.

Python
def count_digits(n):
    return {}
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo do enunciado
    Código do teste
    print(count_digits(12321))
    Esperado:
    {1: 2, 2: 2, 3: 1}
  2. Um dígito
    Código do teste
    print(count_digits(5))
    Esperado:
    {5: 1}

Solução
def count_digits(n):
    if n == 0:
        return {}
    d = count_digits(n // 10)
    d[n % 10] = d.get(n % 10, 0) + 1
    return d

O caso base é n == 0, que devolve o dicionário vazio. A chamada recursiva trata do número sem o último dígito e, no regresso, esse dígito é contado no dicionário devolvido. Assim cada dígito é processado uma vez, sem ciclos.

Voltar à explicação
Calculadora de fraçõesCódigo

PE3, 2020/21

Escreve uma função em Python calculator(expr) que calcula o valor de uma expressão expr. A expressão pode ser uma fração representada por um tuplo (numerador, denominador) ou um tuplo da forma (expr, operador, expr). Os únicos operadores válidos são a multiplicação "*" e a divisão "/", e todos os valores são não negativos. Simplifica o resultado à menor fração inteira. Por exemplo, calculator(((1, 3), "*", (2, 5))) calcula 1/3 · 2/5 e devolve (2, 15).

Python
def calculator(expr):
    return expr
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Multiplicação do enunciado
    Código do teste
    print(calculator(((1, 3), '*', (2, 5))))
    Esperado:
    (2, 15)
  2. Divisão simplificada
    Código do teste
    print(calculator(((1, 2), '/', (1, 4))))
    Esperado:
    (2, 1)
  3. Expressão aninhada
    Código do teste
    print(calculator((((1, 2), '*', (1, 3)), '/', (1, 6))))
    Esperado:
    (1, 1)

Solução
def mdc(x, y):
    while y:
        x, y = y, x % y
    return x

def calculator(expr):
    if len(expr) == 2:
        num, den = expr
    else:
        e1, op, e2 = expr
        e1 = calculator(e1)
        e2 = calculator(e2)
        if op == '*':
            num, den = e1[0] * e2[0], e1[1] * e2[1]
        else:
            num, den = e1[0] * e2[1], e1[1] * e2[0]
    d = mdc(num, den)
    return (num // d, den // d)

O caso base é um tuplo de dois elementos (a fracción). Num tuplo de três, calculam-se recursivamente as duas subexpressões e aplicam-se as regras: multiplicam-se numeradores com numeradores e denominadores com denominadores; na divisão, cruza-se. No fim, divide-se pelo máximo divisor comum para simplificar.

Voltar à explicação

Geradores

Gerador de FibonacciCódigo

PE4, 2020/21

Escreve uma função geradora em Python fib(start, end) que gera a sequência de Fibonacci de inteiros começando no start-ésimo número (start >= 1) e acabando no end-ésimo número (end >= start). Os dois primeiros números da sequência são 1 e cada número consecutivo é a soma dos dois anteriores. Por exemplo, se start = 1 e end = 7, a sequência gerada é [1, 1, 2, 3, 5, 8, 13].

Python
def fib(start, end):
    return
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Sequência completa
    Código do teste
    print(list(fib(1, 7)))
    Esperado:
    [1, 1, 2, 3, 5, 8, 13]
  2. A meio da sequência
    Código do teste
    print(list(fib(4, 6)))
    Esperado:
    [3, 5, 8]

Solução
def fib(start, end):
    i = 1
    a, b = 1, 1
    while i <= end:
        if i >= start:
            yield a
        a, b = b, a + b
        i += 1

A sequência tem de ser calculada desde o início, independentemente de start, por isso o contador i começa em 1. Só se faz yield quando i >= start, e a, b = b, a + b avança dois termos de cada vez.

Voltar à explicação
Gerador a partir de uma lista de intervalosCódigo

PE4, 2019/20

Uma lista de intervalos é uma lista de tuplos que representam intervalos. Cada tuplo representa um intervalo da forma (min, max). Os tuplos aparecem por ordem crescente na lista e os intervalos são disjuntos. Por exemplo, a lista [(1, 1), (3, 5), (10, 15)] representa a sequência completa 1, 3, 4, 5, 10, 11, 12, 13, 14, 15. Escreve uma função geradora generator(intlist) que vai devolvendo com yield o termo seguinte da sequência completa representada em intlist.

Python
def generator(intlist):
    return
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Dois intervalos
    Código do teste
    print(list(generator([(1, 1), (3, 5)])))
    Esperado:
    [1, 3, 4, 5]
  2. Intervalo com vários termos
    Código do teste
    print(list(generator([(10, 12)])))
    Esperado:
    [10, 11, 12]

Solução
def generator(intlist):
    while intlist != []:
        yield intlist[0][0]
        if intlist[0][0] == intlist[0][1]:
            intlist = intlist[1:]
        else:
            intlist = [(intlist[0][0] + 1, intlist[0][1])] + intlist[1:]

Em cada passo, o primeiro valor do primeiro intervalo é devolvido com yield. Se min == max, o intervalo está esgotado e passa-se ao seguinte; senão, incrementa-se o min do primeiro intervalo, avançando para o próximo termo.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.