0Pricing
DSA Interview Prep · Aula

Entrevista simulada cronometrada: problemas fáceis e médios

Resolva três problemas em 45 minutos, verbalize seu raciocínio como faria em uma entrevista real e revise as soluções ideais depois.

Entrevista simulada cronometrada: problemas fáceis e médios é uma aula grátis de DSA Interview Prep no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de DSA Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de DSA Interview Prep inclui 4 aulas no total.

Como usar esta entrevista simulada

Esta lição simula uma sessão real de entrevista de programação. Para cada problema, você deve: (1) lê-lo uma vez, (2) identificar o padrão em até 60 segundos, (3) declarar sua abordagem e sua complexidade, (4) escrever a solução e (5) testar com exemplos. Defina um cronômetro. Um problema fácil deve levar de 10 a 15 minutos; um problema médio, de 20 a 25 minutos.

Não consulte a solução antecipadamente — isso elimina o propósito do exercício. Se você ficar bloqueado depois de 5 minutos, releia o enunciado e procure a palavra-chave que revela o padrão (ordenado? mínimo? todas as combinações? subvetor?). A capacidade de sair do bloqueio sozinho é tão importante quanto a capacidade de resolver rapidamente.

# Mock interview timer simulation
import time

class InterviewTimer:
    def __init__(self, total_minutes):
        self.total = total_minutes * 60
        self.start = None

    def begin(self, problem_name):
        self.start = time.time()
        print(f'TIMER STARTED: {problem_name}')
        print(f'You have {self.total//60} minutes. Go!')

    def checkpoint(self, label):
        if self.start:
            elapsed = time.time() - self.start
            remaining = self.total - elapsed
            print(f'[{label}] Elapsed: {elapsed:.0f}s, Remaining: {remaining:.0f}s')

# Usage in real practice:
timer = InterviewTimer(15)  # 15-minute easy problem
timer.begin('Two Sum')
time.sleep(1)
timer.checkpoint('Identified pattern')

Problema fácil 1: parênteses válidos

Problema: Dada uma cadeia de caracteres contendo apenas '(', ')', '{', '}', '[', ']', determine se a cadeia de caracteres de entrada é válida. Uma cadeia é válida se cada delimitador de abertura for fechado pelo mesmo tipo de delimitador na ordem correta.

Sinal: Pares correspondentes, a ordem importa, o delimitador de abertura mais recente deve ser fechado primeiro → Pilha. Empilhe os delimitadores de abertura; faça pop e verifique o item ao encontrar delimitadores de fechamento. Se a pilha estiver vazia quando tentarmos fazer pop ou ainda tiver itens ao final, a cadeia será inválida. Tempo O(n), Espaço O(n).

def is_valid(s):
    stack = []
    matching = {')': '(', '}': '{', ']': '['}

    for char in s:
        if char in '({[':
            stack.append(char)
        else:
            if not stack or stack[-1] != matching[char]:
                return False
            stack.pop()
    return len(stack) == 0

# Test cases
test_cases = [
    ('()', True),
    ('()[]{}'  , True),
    ('(]', False),
    ('([)]', False),
    ('{[]}', True),
    ('', True),        # empty string is valid
    ('(((', False),    # unmatched opens
    (')]', False),     # close without open
]
for s, expected in test_cases:
    result = is_valid(s)
    status = 'PASS' if result == expected else 'FAIL'
    print(f'{status}: is_valid({repr(s)}) = {result} (expected {expected})')

Problema fácil 2: melhor momento para comprar e vender ações

Problema: Dado um vetor prices em que prices[i] é o preço da ação no dia i, encontre o lucro máximo com uma compra e uma venda (é obrigatório comprar antes de vender). Retorne 0 se não for possível obter lucro.

Sinal: Diferença máxima em que a posição à esquerda deve preceder a da direita → acompanhe o mínimo acumulado enquanto percorre o vetor da esquerda para a direita. A cada dia, o lucro potencial é current_price - min_so_far. Atualize o lucro máximo. Isso é O(n)/O(1) e um caso especial do algoritmo de Kadane.

def max_profit(prices):
    if not prices:
        return 0
    min_price = float('inf')
    max_profit = 0

    for price in prices:
        if price < min_price:
            min_price = price
        elif price - min_price > max_profit:
            max_profit = price - min_price
    return max_profit

# Test cases
test_cases = [
    ([7, 1, 5, 3, 6, 4], 5),   # buy at 1, sell at 6
    ([7, 6, 4, 3, 1], 0),      # monotonically decreasing: no profit
    ([2, 4, 1], 2),             # buy at 2, sell at 4
    ([1], 0),                   # single price: no transaction possible
    ([3, 3, 3], 0),             # flat: no profit
]
for prices, expected in test_cases:
    result = max_profit(prices)
    status = 'PASS' if result == expected else 'FAIL'
    print(f'{status}: max_profit({prices}) = {result} (expected {expected})')

Problema médio 1: soma de três elementos

Problema: Dado um vetor, encontre todas as trincas únicas cuja soma seja zero. A solução não deve conter trincas duplicadas.

Padrão: Extensão da técnica de dois ponteiros para três elementos. Use sort no vetor. Para cada elemento nums[i], use dois ponteiros left = i+1, right = n-1 para encontrar pares cuja soma seja -nums[i]. Ignore duplicatas avançando além dos valores idênticos. Tempo O(n²), Espaço O(1), sem contar a saída. O uso de sort torna simples o tratamento de duplicatas.

def three_sum(nums):
    nums.sort()
    result = []
    n = len(nums)

    for i in range(n - 2):
        # Skip duplicate values for the first element
        if i > 0 and nums[i] == nums[i - 1]:
            continue
        left, right = i + 1, n - 1
        while left < right:
            total = nums[i] + nums[left] + nums[right]
            if total == 0:
                result.append([nums[i], nums[left], nums[right]])
                while left < right and nums[left] == nums[left + 1]:
                    left += 1      # skip duplicate lefts
                while left < right and nums[right] == nums[right - 1]:
                    right -= 1     # skip duplicate rights
                left += 1; right -= 1
            elif total < 0:
                left += 1
            else:
                right -= 1
    return result

print(three_sum([-1, 0, 1, 2, -1, -4]))  # [[-1,-1,2],[-1,0,1]]
print(three_sum([0, 0, 0, 0]))            # [[0,0,0]]
print(three_sum([]))                       # []
print(three_sum([1, 2, -2, -1]))           # []

Problema Médio 2: Subcadeia Mais Longa sem Caracteres Repetidos

Problema: Dada uma cadeia de caracteres, encontre o comprimento da maior subcadeia sem caracteres repetidos.

Padrão: Janela deslizante com um conjunto (ou um dicionário das últimas posições). Mantenha uma janela [esquerda, direita]. Expanda a janela para a direita, incluindo cada caractere. Se um caractere se repetir (já estiver na janela), reduza a janela pela esquerda até remover o duplicado. Registre o maior tamanho de janela observado. Complexidade temporal O(n), complexidade espacial O(mínimo entre n e o tamanho do alfabeto).

def length_of_longest_substring(s):
    char_index = {}    # character -> last seen index
    left = 0
    max_len = 0

    for right, char in enumerate(s):
        if char in char_index and char_index[char] >= left:
            left = char_index[char] + 1  # shrink window past duplicate
        char_index[char] = right
        max_len = max(max_len, right - left + 1)
    return max_len

# Test cases
test_cases = [
    ('abcabcbb', 3),   # 'abc'
    ('bbbbb', 1),       # 'b'
    ('pwwkew', 3),      # 'wke'
    ('', 0),            # empty string
    ('au', 2),          # full string
    ('dvdf', 3),        # 'vdf' (skip the first d)
]
for s, expected in test_cases:
    result = length_of_longest_substring(s)
    status = 'PASS' if result == expected else 'FAIL'
    print(f'{status}: len_longest({repr(s)}) = {result} (expected {expected})')

Problema Médio 3: Troca de Moedas

Problema: Dadas as denominações das moedas e uma quantia-alvo, encontre o número mínimo de moedas necessário para atingir a quantia. Retorne -1 se isso for impossível.

Padrão: DP clássico unidimensional (variante da mochila ilimitada). dp[i] = número mínimo de moedas para a quantia i. Inicialize dp[0] = 0; todos os demais valores = infinito. Para cada quantia de 1 até o alvo, teste todas as denominações de moedas. dp[i] = min(dp[i], dp[i - coin] + 1) para cada moeda válida. Complexidade temporal O(quantia × número de denominações), complexidade espacial O(quantia).

def coin_change(coins, amount):
    dp = [float('inf')] * (amount + 1)
    dp[0] = 0   # 0 coins to make amount 0

    for i in range(1, amount + 1):
        for coin in coins:
            if coin <= i and dp[i - coin] + 1 < dp[i]:
                dp[i] = dp[i - coin] + 1

    return dp[amount] if dp[amount] != float('inf') else -1

# Test cases
test_cases = [
    ([1, 5, 11], 15, 3),      # 11+1+1+1+1... wait: 11+1+1+1+1=5 coins? No: 5+5+5=3
    ([2], 3, -1),              # impossible (only even coins)
    ([1], 0, 0),               # 0 coins for amount 0
    ([1, 2, 5], 11, 3),        # 5+5+1
    ([186, 419, 83, 408], 6249, 20),  # stress test
]
for coins, amount, expected in test_cases:
    result = coin_change(coins, amount)
    status = 'PASS' if result == expected else 'FAIL'
    print(f'{status}: coin_change({coins}, {amount}) = {result} (expected {expected})')

Fluxo de Trabalho para Resolver Problemas sob Pressão de Tempo

Quando o tempo estiver acabando, priorize nesta ordem: (1) uma solução de força bruta funcional com saída correta em vez de uma solução ótima incompleta, (2) trate os casos limite de forma visível, (3) escreva código limpo e legível em vez de usar soluções engenhosas de uma só linha. Os entrevistadores preferem uma solução limpa de O(n²) que passe em todos os casos de teste a uma solução de O(n) com um erro sutil.

Se perceber que sua solução de O(n²) está errada, não a abandone no meio — conclua-a, teste-a e, depois, ofereça-se para otimizá-la se ainda houver tempo. Uma solução ótima escrita pela metade rende menos crédito do que uma solução completa, porém subótima.

# Priority order when time runs out
priority = [
    ('First priority',  'Correct brute-force that passes all test cases'),
    ('Second priority', 'Optimal solution with bugs is WORSE than suboptimal correct'),
    ('Third priority',  'Edge cases handled visibly (empty input, single element, negatives)'),
    ('Fourth priority', 'Clean variable names and readable code'),
    ('Fifth priority',  'Add complexity statement as a comment at the top'),
]
print('Under time pressure, prioritise:')
for priority_level, desc in priority:
    print(f'  {priority_level}: {desc}')

# Adding complexity as a comment
def two_sum_commented(nums, target):
    # Time: O(n), Space: O(n)
    seen = {}
    for i, n in enumerate(nums):
        complement = target - n
        if complement in seen:
            return [seen[complement], i]
        seen[n] = i
    return []

Revisão da Sua Solução: Cinco Perguntas

Antes de dizer "Terminei", faça a si mesmo estas cinco perguntas:

  1. Ela lida com uma entrada vazia? [], '', None, n=0
  2. Ela lida com um único elemento? Vetores de tamanho 1, árvores com um nó
  3. Ela lida com elementos todos iguais? [5, 5, 5, 5], 'aaaa'
  4. Ela lida com values mínimos e máximos? Números negativos, inteiros muito grandes, 0
  5. DeclareI a complexidade temporal e espacial? Notação assintótica com uma breve justificativa

Essas cinco verificações identificam a maioria dos erros em soluções de entrevistas. Os entrevistadores esperam que os candidatos testem suas próprias soluções — eles não informarão que há um erro na sua solução, a menos que você peça um retorno.

# The five edge-case categories with examples
edge_cases = {
    'Empty input':     ['[] empty array', '"" empty string', 'None / null'],
    'Single element':  ['[42]', 'single node tree', 'n=1'],
    'All same':        ['[3,3,3,3]', '"aaaa"', 'uniform grid'],
    'Extreme values':  ['[-10^9, 10^9]', 'INT_MAX + 1 overflow check', '0 as input'],
    'Already sorted':  ['ascending + descending', 'already optimal input'],
}
for category, examples in edge_cases.items():
    print(f'{category}:')
    for ex in examples:
        print(f'  - {ex}')
    print()

# Template for self-testing:
def test_my_solution(fn, test_cases):
    for inputs, expected in test_cases:
        result = fn(*inputs) if isinstance(inputs, tuple) else fn(inputs)
        status = 'PASS' if result == expected else 'FAIL'
        print(f'{status}: {inputs} => {result} (expected {expected})')

Como Lidar com Perguntas de Acompanhamento

Depois de resolver o problema, os entrevistadores normalmente fazem perguntas de acompanhamento. Tipos comuns:

  • "Você consegue fazer isso usando espaço O(1)?" → Procure uma modificação no próprio local ou truques matemáticos
  • "E se n for muito grande?" → Discuta abordagens de processamento em fluxo, paginação ou amostragem
  • "E se o vetor já estiver ordenado?" → Muitas vezes existe um algoritmo mais simples
  • "Você consegue paralelizar isso?" → Identifique subproblemas independentes e discuta MapReduce ou paralelismo de tarefas

As perguntas de acompanhamento avaliam profundidade e adaptabilidade. Diga "Deixe-me pensar por um momento" em vez de tentar adivinhar imediatamente. Uma pausa ponderada é melhor do que uma resposta errada dada com confiança.

# Follow-up answers for classic problems
follow_ups = [
    {
        'problem': 'Find duplicate in array 1..n (space O(n) solution uses set)',
        'follow_up': 'Can you do it in O(1) space without modifying input?',
        'answer': 'Floyd cycle detection: treat array as linked list (slow/fast pointer)',
    },
    {
        'problem': 'Reverse a string (space O(n) with new array)',
        'follow_up': 'Can you do it in-place?',
        'answer': 'Two pointers from both ends, swap until they meet: O(n) time O(1) space',
    },
    {
        'problem': 'Find max in array: O(n) single pass',
        'follow_up': 'What if the array is streamed one element at a time?',
        'answer': 'Same algorithm works! Running maximum handles infinite streams',
    },
    {
        'problem': 'Merge sorted arrays O(n+m)',
        'follow_up': 'What if you have K sorted arrays?',
        'answer': 'Use a min-heap of (value, array_idx, element_idx): O(n log k)',
    },
]
for fu in follow_ups:
    print(f'Problem: {fu["problem"]}')
    print(f'Follow-up: {fu["follow_up"]}')
    print(f'Answer: {fu["answer"]}\n')

Problema para Praticar: Agrupamento de Anagramas

Problema: Dado um vetor de cadeias de caracteres, agrupe os anagramas. Retorne uma lista de grupos.

Padrão: Mapa de frequências como chave. Para cada cadeia de caracteres, aplique sort aos seus caracteres (ou calcule uma tupla de frequências de caracteres) para formar a chave canônica. Agrupe as cadeias por essa chave usando um mapa de dispersão de listas. Complexidade temporal O(n × m log m), onde m é o comprimento máximo da cadeia; complexidade espacial O(n × m). Nenhum laço aninhado é necessário — uma única passagem pelo vetor.

from collections import defaultdict

def group_anagrams(strs):
    # Method 1: sort each string as key
    groups = defaultdict(list)
    for s in strs:
        key = ''.join(sorted(s))   # canonical form
        groups[key].append(s)
    return list(groups.values())

def group_anagrams_v2(strs):
    # Method 2: character count tuple as key (avoids sorting)
    groups = defaultdict(list)
    for s in strs:
        count = [0] * 26
        for c in s:
            count[ord(c) - ord('a')] += 1
        key = tuple(count)   # immutable, hashable
        groups[key].append(s)
    return list(groups.values())

test = ['eat', 'tea', 'tan', 'ate', 'nat', 'bat']
result = [sorted(g) for g in group_anagrams(test)]
result.sort()
print('Groups:', result)
# [['ate','eat','tea'], ['bat'], ['nat','tan']]

print('V2:', [sorted(g) for g in sorted(group_anagrams_v2(test), key=len)])

Autoavaliação Após uma Simulação

Depois de cada entrevista simulada, avalie-se nestas dimensões:

  • Velocidade de reconhecimento de padrões: Você identificou o padrão em <60 segundos?
  • Correção do código: Sua primeira solução passou em todos os casos de teste?
  • Tratamento de casos limite: Você testou entradas vazias, únicas e extremas?
  • Comunicação: Você explicou seu raciocínio durante todo o processo?
  • Consciência da complexidade: Você declarou as complexidades temporal e espacial?
  • Recuperação: Se ficou travado, você mudou de abordagem com naturalidade ou paralisou?

Dê a si mesmo uma nota de 1 a 5 em cada dimensão. Concentre a prática da próxima semana na dimensão com a menor nota. A maioria dos candidatos precisa melhorar o reconhecimento de padrões ou a comunicação — raramente ambos.

# Self-assessment scoring template
def self_assess(pattern_speed, code_correctness, edge_cases,
                communication, complexity, recovery):
    scores = {
        'Pattern recognition (< 60s)': pattern_speed,
        'Code correctness (all tests pass)': code_correctness,
        'Edge case handling': edge_cases,
        'Communication (thinking aloud)': communication,
        'Complexity stated correctly': complexity,
        'Recovery when stuck': recovery,
    }
    total = sum(scores.values())
    max_total = len(scores) * 5
    print('Self-Assessment Results:')
    print('-'*50)
    for dim, score in scores.items():
        bar = '#' * score + '-' * (5 - score)
        print(f'{dim:45s} [{bar}] {score}/5')
    print(f'\nTotal: {total}/{max_total} ({total/max_total*100:.0f}%)')
    weak = min(scores, key=scores.get)
    print(f'Focus area: {weak}')

self_assess(4, 3, 4, 3, 5, 2)  # example scores

Verificação Rápida

Teste sua compreensão dos conceitos de Estruturas de Dados & Algoritmos — Preparação para Entrevistas de Programação desta lição.

Recapitulação da Lição

Nesta lição, você aprendeu: abordar problemas com um fluxo de trabalho fixo — ler, identificar o padrão em 60 segundos, declarar a complexidade, programar e depois testar usando cinco categorias de casos limite, uma solução de força bruta funcional é melhor que uma solução ótima incompleta quando o tempo está acabando e a autoavaliação após cada sessão de prática simulada, em seis dimensões (velocidade, correção, casos limite, comunicação, complexidade, recuperação), concentra a melhoria nas áreas certas. Em seguida, abordaremos em profundidade o tratamento de casos limite e as melhores práticas de comunicação do candidato durante a entrevista.

Perguntas Frequentes

A aula “Entrevista simulada cronometrada: problemas fáceis e médios” é grátis?

Sim — o texto completo de “Entrevista simulada cronometrada: problemas fáceis e médios” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de DSA Interview Prep, atualize para CoddyKit PRO. O curso de DSA Interview Prep inclui 4 aulas no total.

O que vou aprender em “Entrevista simulada cronometrada: problemas fáceis e médios”?

Resolva três problemas em 45 minutos, verbalize seu raciocínio como faria em uma entrevista real e revise as soluções ideais depois. Você pratica DSA Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar DSA Interview Prep?

Nenhuma experiência prévia é necessária. DSA Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Entrevista simulada cronometrada: problemas fáceis e médios”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de DSA Interview Prep?

Sim. Cada aula de DSA Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Guia rápido de reconhecimento de padrões
  2. Entrevista simulada cronometrada: problemas fáceis e médios
  3. Tratamento de casos extremos e comunicação com o entrevistador
  4. Resolução guiada de problemas difíceis: escada de palavras II e dicionário alienígena
← Voltar para DSA Interview Prep