Como progredir enquanto estuda para programar entrevistas

Ficar preso nunca é divertido. Especialmente quando você está trabalhando muito duro. E, no entanto, acho que isso acontece com pessoas que se preparam para programar entrevistas o tempo todo.

Você faz um trabalho consistente. Você passou por centenas de problemas de prática e reservou uma hora todos os dias para estudar. Mas você simplesmente não está progredindo.

Mesmo depois de todo esse trabalho de preparação, você ainda sente que cada problema é um novo desafio que você não sabe como resolver. Você pode resolver os problemas na maioria das vezes, mas não parece que está ficando muito mais fácil.

Quando trabalho com clientes de coaching 1: 1, essa é exatamente a situação em que os encontro. E em quase todos os casos, uma vez que identificamos a coisa (ou coisas) que os impedem, eles experimentam grandes avanços. Resolver esses problemas garantiu a meus clientes empregos na Amazon, Bloomberg, Uber e muito mais!

Então, o que exatamente está prendendo você? O que está impedindo você de fazer o progresso que deseja? Neste artigo, mostrarei os dez problemas mais comuns contra os quais as pessoas lutam. Mas um aviso justo: pode ser muito difícil identificar esses problemas em você mesmo. Se você realmente deseja resolver seus problemas, recomendo trabalhar com um coach.

1. Desenvolva uma base sólida

Já falei sobre esse assunto antes, mas uma das chaves mais importantes para o sucesso na codificação de entrevistas é ter uma base sólida nos fundamentos da Ciência da Computação.

Com o tempo, desenvolvi muitas técnicas diferentes para ajudar meus alunos a melhorar a resolução de problemas em suas entrevistas, como o método FAST. No entanto, nenhuma dessas técnicas é valiosa se você não tem fundamentos sólidos em seu currículo.

Por exemplo, o método FAST foi desenvolvido para ajudar os alunos com a programação dinâmica. A primeira etapa do método FAST é encontrar uma solução recursiva inicial de força bruta. Isso é algo que você precisa ser capaz de fazer por conta própria para que o método FAST seja útil para você. Mesmo que você entenda a metodologia, não ajudará se você não souber como obter essa solução inicial.

Se você tem fundamentos sólidos, a recursão é algo que não deve ser difícil para você. É um tópico que surge com freqüência suficiente para que você possa explorá-lo quando quiser.

Esse é o caso com todas as outras estruturas de dados e algoritmos fundamentais. Se você não sabe como implementar uma lista vinculada, não importa quantos truques você aprenda para resolver problemas de lista vinculada.

Se você não tem um histórico formal de ciência da computação ou simplesmente descobre que as técnicas de solução de problemas recomendadas para entrevistas de codificação não estão realmente ajudando, então seu primeiro passo deve ser dedicar-se a aprender todas as estruturas e algoritmos de dados fundamentais.

A melhor maneira de fazer isso é fazer o curso de algoritmos e estruturas de dados MIT (Python) ou Princeton (Java). Compre o livro, faça as tarefas e faça os exames. Se você trabalhar, poderá concluir o curso facilmente em 3 meses ou menos e terá uma base sólida para seguir em frente.

2. Obtenha mais experiência de codificação

Você já tentou fazer algo pela primeira vez? Quando eu estava aprendendo a tocar violão, levava 30 segundos para obter o dedilhado de um acorde básico. Em teoria, eu poderia tocar qualquer música se tivesse tempo suficiente e as tabelas de acordes na minha frente, mas não soaria muito bem.

Às vezes trabalho com alunos que estão em uma posição semelhante com sua codificação. Eles simplesmente não alcançaram um nível de proficiência ainda em que possam escrever facilmente o código em sua entrevista.

Em teoria, o componente de codificação da entrevista deve ser a parte fácil. Desde que você tenha praticado em um quadro branco, a parte difícil da sua entrevista deve ser desenvolver uma solução antes de escrever uma linha de código. Se isso não for verdade, provavelmente você precisará melhorar suas habilidades de codificação.

Existem também alguns grupos que são mais afetados por esse problema do que outros. Principalmente, aqueles que têm menos experiência em codificação. Costumo ver graduados do bootcamp, alunos de Mestrado que mudaram para Ciência da Computação em seu mestrado de um campo diferente, ou gerentes de longa data que simplesmente não codificam há um tempo lutando ao máximo com a codificação.

A chave aqui é simplesmente obter mais prática de codificação e, de preferência, fazer isso em um ambiente onde você está recebendo bons comentários sobre seu código. Uma das melhores maneiras de fazer isso é contribuindo para projetos de código aberto. Essa não é apenas uma ótima maneira de mostrar sua experiência, mas você terá o benefício de revisões de código completas e de aprender como trabalhar em um ambiente de produção.

Se você é novo no trabalho com código aberto, o First Timers Only é um ótimo recurso para quem deseja começar. Eles compartilham tutoriais sobre como contribuir e compilaram uma lista de projetos em potencial que seriam bons para iniciantes.

3. Aborde estrategicamente cada pergunta da entrevista

Quando vai para a batalha, qualquer general que espera ter sucesso tem um plano detalhado. Se quiser ter sucesso em sua entrevista, você também precisa ter um plano detalhado.

O plano mais comum que vejo para resolver problemas de entrevista é parecido com o seguinte:

  1. Olha o problema
  2. Pense no problema
  3. Encontre uma solução
  4. Escreva a solução
  5. Sucesso

Porém, você percebe um problema aqui? Esperançosamente, a primeira coisa que você perguntou foi "Como faço para encontrar uma solução?" Este plano carece totalmente de qualquer tipo de estratégia para encontrar a solução. Ele assume que a solução simplesmente aparecerá.

E é assim que a maioria das pessoas pensa sobre os problemas das entrevistas. Eles memorizam toneladas de soluções com a esperança de que uma delas seja semelhante o suficiente ao problema que enfrentaram na entrevista para que uma solução se materialize magicamente.

Isso é, na melhor das hipóteses, arriscado.

Uma maneira muito melhor de entrevistar é ter um plano de jogo claro de como você abordará cada entrevista e cada problema dentro da entrevista. Aqui está um esboço de como você pode abordar uma entrevista de uma hora:

[0: 00-0: 05] Esteja instalado e certifique-se de que entendeu completamente o problema que eles estão perguntando. Trabalhe com qualquer exemplo de entrada fornecido.

[0: 05–0: 10] Descubra uma solução de força bruta para o problema. Não há codificação neste ponto, apenas converse e desenhe as imagens se achar útil. Se você não conseguir encontrar uma solução de força bruta, tente resolver o problema manualmente e traduzir o processo para resolvê-lo em um algoritmo.

[ 0: 10–0: 15] Otimize sua solução. Use esses 5 minutos para descobrir a melhor solução absoluta possível neste período de tempo. Ao comparar soluções, considere as complexidades do tempo.

[0: 15–0: 35] Codifique sua solução. Mesmo que não seja ideal, é melhor ter uma solução completa e não ótima do que uma solução incompleta e ótima.

[0: 35–0: 50] Teste seu código e corrija quaisquer problemas. Isso é extremamente importante. Não importa se seu código não está perfeito na primeira vez, mas é melhor você ser capaz de identificar os erros.

[0: 50-1: 00] Perguntas para o seu entrevistador.

Seguindo essas etapas, você consegue duas coisas simultaneamente. Primeiro, você orça seu tempo de maneira eficaz. A coisa mais frustrante do mundo é ficar sem tempo quando você sabe como resolver o problema.

Em segundo lugar, essas etapas o ajudarão a garantir que você sempre encontrará uma solução. Começando com a solução de força bruta e otimizando, você pode quase garantir que, pelo menos, encontrará alguma solução. Muitas vezes, a solução ideal não é necessária se você se sair bem no resto da entrevista.

4. Considere diferentes soluções possíveis

Você sabia que a maioria das perguntas da entrevista tem mais de uma solução correta? Eu sei, chocante, certo? No entanto, muitas pessoas encontram uma solução e param por aí, sem procurar mais.

Isso sempre me decepciona. Muitas vezes, há outra solução que teria sido ainda melhor e eles estavam tão perto. Ou talvez houvesse soluções comparáveis ​​com diferentes compensações.

Por exemplo, considere este problema:

  • Uma solução tem O(n)complexidade de tempo e O(1)complexidade de espaço
  • Outra solução tem O(log n)complexidade de tempo e O(log n)complexidade de espaço

Qual dessas soluções é melhor?

Bem, isso depende do que estamos realmente procurando. Se tivermos um grande conjunto de dados e pouca memória, a primeira solução pode ser melhor. No entanto, se a memória não é um problema, então obviamente queremos ir com a segunda solução.

A chave aqui é que, embora em alguns casos possa haver uma "melhor" solução, há muito mais problemas em que você pode fazer diferentes trocas e precisa decidir quais fazer. Como entrevistador, adoro ver candidatos que avaliam as diferentes possibilidades.

Quando estiver pensando em soluções, pare um momento para pensar em outras maneiras de resolver o mesmo problema. Você poderia fazer concessões que melhorariam o uso do espaço em relação ao tempo ou vice-versa?

Por fim, você deve sempre considerar a complexidade de espaço e tempo de cada solução que encontrar. Isso fornece uma maneira objetiva de avaliar quais soluções são melhores do que outras e ajuda a tomar uma decisão mais informada sobre qual solução escolher. Se você tiver várias soluções comparáveis, discuta com seu entrevistador e decida colaborativamente qual seria a melhor abordagem.

5. Comece com a solução de força bruta

Já mencionei isso de passagem na dica 3, mas um dos maiores erros que as pessoas cometem ao tentar resolver problemas de entrevista é que elas imediatamente tentam encontrar a solução ideal para o problema.

Mas deixe-me perguntar o seguinte: o que é melhor, uma solução de força bruta ou nenhuma solução?

Vou te dizer que encontrar uma solução de força bruta é 1000% melhor do que não encontrar uma solução. E se você começar tentando encontrar imediatamente a solução ideal, é fácil ficar preso e acabar sem uma solução completa no final da entrevista.

Embora você realmente não precise codificá-lo, eu recomendo pelo menos mencionar brevemente como você poderia resolver o problema com uma solução de força bruta antes de tentar otimizar sua solução. Isso realiza duas coisas importantes:

  1. Dá a você um plano alternativo. Se você tentar otimizar sua solução e falhar, você pode parar após 5 ou 10 minutos e apenas codificar sua solução de força bruta. Você ainda pode passar na entrevista. Nem todos os problemas têm soluções ideais.
  2. Ajuda a esclarecer o problema. Definir uma solução de força bruta pode ajudá-lo a entender exatamente o que está envolvido em chegar a uma solução para este problema. Essa é a chave. Entender o problema dessa forma profunda tornará mais fácil otimizar.

Tentar encontrar imediatamente uma solução ideal pode parecer a abordagem certa, pois economizará um tempo valioso. No entanto, acho que a confusão que resulta dessa abordagem geralmente perde muito mais tempo do que você ganha.

Começar com uma solução de força bruta oferece clareza e um ponto de partida para tornar tudo mais fácil.

6. Planeje a solução completa antes de codificar

Existem quadros brancos super sofisticados por aí. Mas as chances são de que o quadro branco que você usará não terá a opção de copiar e colar. Isso significa que você deseja ter um bom esboço de seu código antes de escrevê-lo.

Freqüentemente, as pessoas começam a escrever o código assim que perguntam um problema na entrevista. Agora está tudo bem se você quiser ir em frente e definir seu método antecipadamente, mas essa deve ser a extensão do código que você escreve até que tenha trabalhado totalmente a solução. Escrever mais código do que isso é um erro crítico por dois motivos.

Primeiro, como eu disse, os quadros brancos não possuem a funcionalidade de copiar e colar. Isso significa que, se você quiser mover linhas de código, terá que apagá-las e reescrevê-las ou desenhar setas em todos os lugares. Você realmente não quer que seu quadro branco fique assim:

Manter o quadro branco organizado é mais fácil para você e seu entrevistador. É mais fácil para eles entenderem sua solução e é muito mais fácil para você acompanhar o que está acontecendo. E se você decidir apenas reescrever as coisas em vez disso, estará perdendo muito tempo valioso.

O outro problema de começar a codificar logo de cara é que isso pode prendê-lo a uma maneira específica de pensar sobre o problema. Falaremos mais sobre isso no ponto 7, mas isso pode ser extremamente prejudicial para o desempenho da entrevista.

Imagine que você vê um problema e uma solução imediatamente vem à mente. Você começa a codificá-lo, mas percebe que não é mais o ideal. É improvável que você queira apagar tudo e começar de novo. E mesmo que o faça, você ficará preso a esse modo de pensar.

Existem problemas em que a solução ótima não tem nenhuma relação com a solução de força bruta e as tentativas de otimizar a solução de força bruta falharão. Se esperar para começar a codificar, você evita prender sua mente nessa forma de ver o problema.

É por essas preocupações que sempre sugiro que você entenda totalmente a solução que deseja codificar antes de escrever o código. Desenhe imagens, escreva pseudocódigo, faça tudo o que for preciso para entender a solução. Depois de começar a codificar, deve ser trivial porque você já sabe exatamente o que escrever.

7. Tenha o quadro geral em mente

Um dos maiores problemas que vejo para desenvolvedores mais experientes é que eles ficam totalmente presos no meio de um problema. Eles começam a ficar obcecados se o loop deve ou não ser <; N or &lt; = N e não consigo descobrir qual é a abordagem certa.

Este é um exemplo perfeito de como perder a floresta pelas árvores. A questão que eles estão tentando resolver passa a ser “Como escrevo este loop corretamente?” em vez de "Qual a finalidade desse loop no contexto mais amplo do meu código?"

Um exemplo perfeito disso é um problema em que você tenta usar a estrutura de dados errada. Digamos que você esteja armazenando os valores indexados de 1-Ne decida que deseja usar um HashMap. Você pode inserir 1 -> value 1, 2 ->valor2 e assim por diante.

Mas agora, quando você quiser iterar sobre eles em ordem, será uma dor porque você precisa obter todos os elementos do HashMap e classificá-los. No entanto, se você deu um passo para trás e olhou o que está realmente tentando fazer, você deseja apenas armazenar o valor em cada índice e iterar por meio deles. Uma matriz seria uma estrutura de dados muito mais fácil de usar.

Agora você pode estar pensando: “Eu nunca faria uma coisa estúpida como essa”, mas acredite em mim, isso acontece o tempo todo. Seu processo de pensamento é não linear quando você está resolvendo problemas, então você pode ter pensado que precisava de um HashMap por causa de alguma outra linha de pensamento que abandonou desde então.

É por isso que é tão importante parar de vez em quando, especialmente se você começar a fazer algo que parece desafiador e olhar para trás, para o panorama geral do que está tentando fazer. Sempre que você estiver fazendo algo que parece desnecessariamente complicado, olhe para seu objetivo final e veja se consegue simplificar sua abordagem.

8. Use a abstração a seu favor

Eu amo perguntar problemas complicados de entrevista. Se um problema envolver vários componentes diferentes, você, como entrevistador, terá ótimos insights sobre como um candidato gerencia seu pensamento quando há tanto para lidar ao mesmo tempo.

A chave para resolver esses problemas com sucesso é usar a abstração. Basicamente, isso significa dividir seu código em funções menores com propósitos mais específicos.

Considere um exemplo simples. Digamos que desejamos imprimir uma lista vinculada na ordem inversa. Depois de resolver este problema, percebemos que há uma O(n)solução de tempo e espaço para o problema usando uma pilha (empurre cada elemento para a pilha à medida que iteramos sobre a lista e, em seguida, pop cada item e imprima), mas podemos resolver o problema em O(n)tempo e O(1)espaço invertendo a lista encadeada.

Agora seria fácil reverter a lista vinculada em nosso código, mas e se tivéssemos uma função para fazer isso por nós? Isso tornaria nossas vidas muito mais fáceis. Nós apenas chamamos a função na lista vinculada, iteramos sobre tudo na lista e a imprimimos, e então invertemos a lista novamente para que retornemos nossa entrada ao estado original.

Com essa lógica, podemos isolar o processo de reverter uma lista vinculada e pensar em como fazer isso de forma eficaz. Embora esse problema seja um exemplo muito simples, é fácil ver como isso reduz a quantidade de complexidade em que temos que pensar a qualquer momento.

Com problemas mais complicados, recomendo que você se pergunte "Qual função, se existisse, tornaria minha vida mais fácil agora?" Se houver uma função ou funções claras, escreva seu código assumindo que essas funções já existam. Então você pode voltar depois e implementar essas funções, agora que o resto do seu código já funciona.

Isso tem várias vantagens:

  1. Se o tempo acabar, você ainda terá um código basicamente funcionando. A abstração permite que você se concentre na estrutura geral sem ter que se prender a minúcias. Se você tiver tempo extra, pode se preocupar com as minúcias, mas mesmo se não tiver, fica claro para o seu entrevistador que você sabe o que está acontecendo.
  2. Clareza de pensamento e código. Eles dizem que uma mesa limpa significa uma mente limpa e o mesmo é verdade com o código. Quanto melhor você organizar seu código e dividi-lo em componentes gerenciáveis, mais fácil será pensar a respeito.

Acho que quanto mais envolvido está o problema, mais valioso pode ser dividir as coisas em componentes gerenciáveis.

9. Teste seu código

Quando estamos fazendo algo novo, tendemos a esquecer muitas das coisas que já sabemos. Presumimos que as coisas que já sabemos não se aplicam.

Considere este exemplo: Tenho aprendido a tocar violão nas horas vagas. Eu estava lutando para progredir, então pedi ajuda a meu professor, e ele sugeriu que eu escrevesse algumas metas sobre o que queria realizar. “DUH”. Eu escrevo sobre esse tipo de coisa o tempo todo, mas não consegui fazer a conexão entre a preparação da programação para a entrevista e a prática de guitarra.

Da mesma forma, descobri que muitos alunos se esquecem de aplicar as melhores práticas que conhecem da codificação do mundo real em suas entrevistas. Eles presumem que as entrevistas de codificação são totalmente diferentes, então as coisas que eles fariam normalmente não se aplicam.

Uma das coisas que as pessoas esquecem o tempo todo é testar sua solução de entrevista. Mas você já comprometeu código no mundo real sem testá-lo completamente primeiro?

Você testa seu código porque deseja ter certeza de que está correto e que faz o que você acha que deveria fazer. Isso é ainda mais importante no ambiente estressante de uma entrevista, porque você está mais sujeito a cometer erros.

A chave para testar suas soluções é realmente percorrer o código linha por linha, rastreando os valores de cada variável e efetivamente “executando” o código. Se você acabou de ler o código em alto nível, pode facilmente deixar de perceber problemas menores com seu código. Gravei um vídeo que demonstra exatamente como percorrer e testar seu código.

Descobri que muitos alunos se estressam por ter seu código perfeito na primeira vez e, embora essa seja uma boa aspiração, raramente acontece. Quase nunca acontece no mundo real, então por que você espera que aconteça no ambiente mais estressante da entrevista? No entanto, se você testar seu código completamente, poderá corrigir quaisquer bugs e ainda assim acabar com uma solução A +.

10. Obtenha um bom feedback

Fazer entrevistas no mundo real é uma ótima maneira de melhorar suas entrevistas. Você pode ficar mais confortável com a experiência e ter muitas oportunidades de sucesso. Uma estratégia freqüentemente recomendada é agendar uma tonelada de entrevistas com aqueles com os quais você está menos animado primeiro. Dessa forma, você começa a praticar entrevistas onde realmente não se preocupa com o resultado, para estar mais preparado quando as entrevistas importantes chegarem.

Embora eu ache que essa estratégia tem méritos, há uma falha fatal: as empresas são notoriamente ruins em fornecer feedback significativo.

“Então”, você pode dizer, “Quem se importa? Posso apenas julgar meu próprio desempenho. ”

Bem, sim, é verdade, mas pode ser muito difícil se julgar. Você não sabe quais critérios seu entrevistador está procurando (apenas obter uma solução ideal para um problema pode não resolver). E se você está lutando para ter sucesso, é provável que haja algo que você não está vendo.

É por isso que entrevistas simuladas e, acima de tudo, trabalhar com um coach são tão importantes. Entrevistas simuladas oferecem a oportunidade de obter feedback detalhado sobre seu desempenho. O entrevistador também pode dizer se há coisas que você não percebeu

Se você realmente quer se sair bem em suas entrevistas, também recomendo trabalhar com um treinador além das entrevistas simuladas. Entrevistas simuladas são pontos de dados individuais. Eles dizem que em um problema específico em um determinado momento, você se saiu bem ou mal. No entanto, um coach pode examinar todos esses pontos de dados e ajudá-lo a fazer conexões. Eles podem ajudá-lo a ver as coisas específicas nas quais você precisa trabalhar para melhorar diferentes aspectos de seu desempenho na entrevista.

Em última análise, as entrevistas simuladas fornecem pontos de dados e os treinadores ajudam a conectar os pontos. Obter esse tipo de feedback é a melhor maneira possível de acelerar o andamento da entrevista.

Vez após vez, vejo pessoas parando em suas entrevistas. E quase sempre é por um dos motivos descritos acima. Se você não está fazendo o tipo de progresso que deseja, leia este artigo com atenção. Identifique sua (s) área (s) de problema e trabalhe para corrigi-la. Com o tempo, você poderá refinar sua entrevista e começar a receber as ligações que deseja ouvir.