Ace the coding interview: How I got offers at Google and Facebook, twice!

Matthew Leong
8 min readApr 23, 2021

In 2017, I received offers from Facebook, Google, Microsoft. I thought I had just gotten lucky. But in 2019, I followed the same preparation process and replicated the results: After receiving offers from Facebook, Google, Snap, Square, and Uber, I realized I had found a repeatable process to ace coding interviews. My process was honed through hundreds of hours studying for technical interviews and over 100 hours of being interviewed at actual companies. I wrote up a guide to share with friends, who found it to be valuable and encouraged me to share it with a wider audience.

This guide only covers coding questions. My process offers many tips for efficient practice, but few shortcuts, and is not the “4-Hour Workweek” of interview prep guides. Rather, it’s a systematic approach that takes time and builds a strong interviewing foundation.

What to expect: It’s a grind

This overloaded graphic captures the emotional journey through the interview process that follows the exponential results curve I’ve experienced.

Sleepless nights. Sweaty hands. Teary eyes. Prepping and interviewing for SWE jobs is grueling because interviewing is a skill in itself. Being a good programmer does not make you a good interviewer. So as you develop your interview skills, your progress will follow an exponential results curve— you won’t see results for a while, you’ll face lots of rejection, and it’s demoralizing. But your knowledge and experience compounds, and as you push forward you will reach an inflection point where you rapidly improve and start nailing interviews consistently.

The Process

Preparation can be broken down into two areas:

  1. Knowledge: Do you know your stuff?
  2. Nerves: Can you perform under pressure?

Building your knowledge 🤓

Targeted drilling is the most efficient way to improve on your weaknesses.

Step 1: Diagnostics

To identify areas you need to work on (it’s okay if it’s all of them), use the Cracking the Coding Interview (CTCI) “Interview Questions” chapters as a diagnostic test since it covers all the major question categories. Go through one chapter at a time. If you get through a few problems in one category (ex. Arrays) and they seem easy, move on to next chapter. Otherwise, work through all the problems in a chapter. As you go through the book, jot down your confidence with each section. I use a 4 point scale, where 1 = No confidence, 2 = Shaky, and 3 = Passable, and 4 = Rock solid. After going through the CTCI chapters you will end up with something like this:

  • Arrays and Strings: 2
  • Linked Lists: 1
  • Stacks and Queues: 3
  • <Repeat for every chapter>

Step 2: Efficient practice

Use Python for speed. It’s the best language for coding interviews because the syntax is concise and it contains utilities for arrays and string manipulation, allowing you to code quickly. The faster you can code, the more attempts you have for each question. Python lets you fail fast and learn fast during practice, and more importantly during the interviews. I learned Python specifically for interviewing and it paid off.

Only attempt Easy and Medium difficulty questions on LeetCode. Hards take too long and as a result are rarely if ever asked in actual interviews, since interviews are typically only 45 min long. You get the most bang for your buck with the Easy/Mediums.

Drill one category at a time. Start with your weakest area and LeetCode the crap out of it. Drill one category at a time (e.g. only Array questions) in sets of 5–10 questions. As opposed to doing a mixed bag of question categories, drilling individual categories provides the repetition you need to build intuition around solving specific problem types. As you work through one category, let’s say Arrays, you will observe the patterns and strategies that can help you solve any Array question.

Get LeetCode Premium. I pay for premium because it helps me see which problems are popular and I always start with the most popular ones in each category since I want practice questions I’m likely to see in real interviews. The difference between a bad offer and a good offer is tens to hundreds of thousands of dollars a year, so $35/mo is a small price to pay to improve your chances. I’ve also heard AlgoExpert is well worth the price.

Cap each question at 30 minutes. Start a timer for 30 minutes. If it runs out and you’re not close, look at the answers since spending more time has diminishing returns.

Calculate the runtime complexity. Since your interviewer will always ask you for runtime complexity, practice on every question.

Think out loud. Since you’ll have to talk while you code during an interview, practice thinking out loud so it becomes second nature.

Review popular questions you found difficult a few days later. This reinforces your learnings and being able to nail all the popular questions builds a strong foundation. After all, most questions are just a variation of the common ones.

How much drilling should you do? I would shoot for at least a comfort level 3 in every category before moving onto Part 2: Nerves. Hopefully you’ll be at a 3 or 4 in every category before doing real interviews. For reference during my first interview prep period I practiced roughly 150 questions. My second time around I re-did about 100 I’d previously done before + 50 new ones. I’m a strong believer in focusing on the most common questions hence the overlap.

TL;DR for Part 1 — Do CTCI to diagnose weaknesses, then drill on Leetcode. Only do Easy/Medium. Use Python.

Conquering your nerves 🥵

Getting your nerves under control is equally important as knowing your stuff. Even if you’re great at solving problems alone, it’s a completely different experience to have someone watching your every thought and mistake and it will throw you off your game —during one of my first interviews I couldn’t even print out the elements of an array backwards because I was so nervous. The key to minimizing your nerves is getting as much time as possible simulating high pressure live interview situations so you feel comfortable during the real thing.

Step 1: Simulate the real environment
Now that all interviews are done virtually, set up your desk and laptop exactly as you would in a virtual interview. Open up a Zoom call. Use Coderpad to write and run your code in an environment without autocomplete.

Note about white-boarding: In the past with physical onsite interviews, you would want to practice on an actual whiteboard. I also have a friend who asks to use a laptop even in whiteboard sessions and he has never been denied.

Step 2: Have someone watch you
You need a live person watching you while you code and talk out loud to simulate the pressure of a live interview. Ideally this person is a software engineer and can act as a proctor, but in the worst case just get any person — your mom, friend, or sibling — to just be there watching you. Since interviews are now all virtual, have them proctor you through a Zoom call.

Step 3: Do a bunch of practice interviews
If your proctor is a SWE, have them pick a question you’ve never seen before, then set a timer for 35 minutes and begin. Each person has their own interview style, but I used the format below for all my successful interviews.

Recommended Live Interview Format (35 min)

  1. Clarification (~2 min): Restate the problem multiple times and make sure they confirm your understanding is correct. Ask clarifying questions for ~2 minutes even if you think you understand the question. 90% of interviewees jump straight to coding and will be penalized by the interviewer for poor communication. Ask about inputs, edge cases (do we have to handle null values, empty arrays, etc.).
  2. Start with the naive solution (~3 min): In most questions, there is a trivial, brute force approach. It’s good to throw out that solution to get started. You can say “I’m going to start off with the naive solution, and then we can improve from there, how does that sound?” You can write some pseudocode on the board/Coderpad for the brute force but I usually just think out loud and come up with it. Then from there, you can say “okay how can we improve on this?”
  3. Optimize the naive solution (~10 min): Very few questions have O(N²) solutions or worse, so you can almost assume they’re looking for O(N) or O(NlogN) or O(logN). Work on a low-fi pseudocode solution, since this will make it easier to modify your solution because you’ll make some mistakes while you explore. Try not to spend more than 10 minutes on a barebones pseudocode solution. At this point you should have the runtime. State the runtime and ask your interviewer if it’s good enough.
  4. Translate the pseudocode into real code (~15 min): You may not be 100% confident in your solution but you’re against the clock and have to get started. Turn your solution into real code. It’s okay to write code in silence for a few minutes at a time, but make sure to keep the interviewer in the loop as you go. Write down any test cases you think of along the way. Re-check your runtime.
  5. Test thoroughly (5 min): Look at the test cases that you’ve come up with. Any more to add? Go down the list and test each case. Print out local variables’ values so you can keep track of them as they change. Make sure you hit every line of your code with testing. This means if you have a bunch of if statements, make sure you go into every if statement and every loop.

TL;DR for Part 2— Simulate the real environment as closely as possible.

Random tips

  1. Think out loud — You need to practice talking out loud for while you code. When you’re silent, the interviewer has no way to assess you. But it’s okay to be silent for periods of time to fully focus.
  2. Leverage Stubs — Add stubs for trivial functions and say you’ll implement them later. Your interviewer likely won’t make you implement them especially if you’re short on time and it will save you precious time to tackle the meat of the problem. A simple example would be if you need to capitalize the first letter of a list of strings, you can pretend you have a helper that does that and save 2 minutes of implementing that helper function.
  3. Write down test cases as you go — As you are writing code, you’ll likely think of edge cases to check. Quickly jot them down in a comment but continue writing the code so you don’t lose your train of thought but also will remember to go back to test later.
  4. Think through the lens of data structures — remember those areas you drilled in LeetCode / CTCI? (Arrays, LinkedLists, Trees, Maps, Stack/Queue, DP, Recursion). The question they’re asking must fit into one of these categories, so figure out which ones are appropriate. Using the right data structure will usually get you halfway to your solution.
  5. Pace yourself — Exercise well. Eat well. See friends. Have some fun. Stay sane, it’s a long process.

Bonus tip: Ordering your interviews

You’ve put in the work and you’re ready to schedule interviews! Order your interviews from least to most desirable. Despite your best efforts to simulate real interviews, you’ll probably still fail your first 5 real interviews simply because it’s so damn nerve wracking. Because these “throwaway” interviews are unavoidable, try and line up your interviews from least to most desirable. After the first five, your success rate will improve. For reference, I’ve probably failed ~75% of my interviews, but since I saved all my most important interviews for the end when I was at peak performance, I was able to secure the jobs I desired most.

Final Thoughts

It’s a grind but you’ll get through it. At times you might question your motivation or be angry at the fact that technical interviews are a poor way to assess your engineering abilities. It is what it is. Just know that if you put in the time, you’ll see results. Good luck 😊.

Future topics I hope to cover:

  • Sourcing interviews
  • System design interview: iOS focus
  • Behavioral interview prep
  • Negotiating offers

--

--

Matthew Leong

Stanford CS, 2017. FB > Flameingo > Google > Working on fun apps!