Love them or hate them, coding interviews are often a necessary part of getting a software engineering job. The format used to be writing solutions to algorithmic problems on a whiteboard. Lately, with the pandemic, this has all moved to online platforms. Many people despise this part of the interview since the questions asked can be very different from the day to day work of a typical engineer.
For senior engineering positions, the questions are more challenging, and interviewers expect a higher standard. I enjoy this extra challenge and received several offers for senior positions during my last round of interviews. As a result, I keep getting asked for advice on how to pass these harder interviews. Now, after forwarding my friends the same email a bunch of times in the past year, I’m sharing my advice more broadly.
The intended audience for this post is people who have passed basic coding interviews before but want to up their skills. Therefore I’ll skip the discussion of the interview format and instead focus on:
- How to get prepared
- Choosing the right practice problems
(plus my list of the 12 best problems to practice with)
- Knowing the right things
- A recommended study plan
How to get prepared
There are many online interviewing platforms out there, but I highly recommend using Leetcode for the following reasons:
- It has 1000s of sample problems
- Many of the problems have come up in real interviews
- Most problems include multiple sample solutions with detailed explanations to help you sharpen your skills
- There is a grading scale which you can use to identify the harder problems more likely to come up in a senior engineering interview
Leetcode classifies its problems into three difficulty levels: easy, medium, and hard. The classification system isn’t perfect. It depends on your background/strengths as to what you consider easy or hard. I’ve encountered “easy” problems that I got completely stuck on and couldn’t solve, and I’ve also encountered “hard” problems that I blazed through no problem. Still, these classifications are a good starting point. You can also always look at the number of solves vs. number of attempts to get additional info on the difficulty level.
Where should you focus your time? Solve many easy problems or focus on a few hard ones? In my experience interviewing at 15 companies, I’ve never encountered more than a Leetcode medium question, even when interviewing for L6 level positions. The hard problems usually have one of three flaws which prevent them from being good candidates for an actual interview question:
- The problem takes too long to describe
- The solution requires a lot of code
- The solution requires knowledge of a relatively obscure data structure or mathematical theorem, or it requires a “trick” which you either see or you don’t
Should you just avoid the Leetcode hard questions entirely? Not at all! Just because they won’t come up in a real-world setting doesn’t mean there is no value to practicing them. In fact, in my opinion, solving a couple of hard problems was a better use of my time preparing for interviews than churning through many medium problems. There are a few reasons for this:
- The hard problems often teach you multiple concepts at once. Rather than just using a single data structure, you’ll need to combine various data structures creatively.
- Solving hard problems gives you a huge confidence boost. If you solve a few hard problems, you’ll be shocked at how easy the actual interview questions feel.
Overall, I advise starting with medium problems, then adding harder problems as time permits. If you don’t have time to progress beyond medium problems, you should be fine — that’s all you’re likely to see in an interview. However, if you make an effort to solve harder problems, you will boost your understanding and confidence — making your interview success inevitable.
Choosing the right practice problems
Not all problems are created equal. As I mentioned above, some hard problems are either improperly classified or they require a trick/esoteric knowledge. It is not worth wasting your time on these problems.
How do you know which problems are the ones worth solving? Unfortunately, it’s not possible to know ahead of seeing the solution. That’s why I kept a list of my favorite problems. I’ve been sharing this with anyone who emails me for advice.
Here are some questions I would recommend because they are both adequately categorized as hard, and solving them is hugely beneficial for learning:
- Trapping rain water
- Merge K sorted lists
- Integer to English words
- Serialize and deserialize binary tree
- Palindrome pairs
- Regular expression matching
- Design search autocomplete system
- Parse lisp expression
- Maximum vacation days
Here are some questions that, in my opinion, are even harder than the others and maybe ought to be in a “very hard” category. I wouldn’t recommend doing these until you’ve done most of the others, but they can be extremely valuable for building confidence and knowledge:
Finally, here are some hard problems which I would not recommend as they required a trick or relatively obscure knowledge. Don’t waste your time on any of these problems.
None of these lists are complete, of course. They are simply all of the hard problems I solved in my last round of interview practice — so I can speak about them based on experience.
Knowing the right things
All of the above-recommended problems should be solvable provided you have the right background knowledge. This may require some review. Fortunately, Leetcode lets you filter medium problems by data structure to give yourself extra practice on any unfamiliar areas.
Know your data structures really well. This means being super comfortable with the “big 5”: Lists, Arrays, Sets, Trees, and Maps (arguably the most essential data structure in computer science). With Hard problems you need to know a few more. In order of priority: Heaps, Tries, Doubly-Linked Lists, Union-Find, and for bonus points self-balancing binary trees.
On top of data structures, you also have to know when to recognize a dynamic programming problem. The trick I use is to check “does my next choice depend on my previous choices?” If the answer is no, then it is perfect for dynamic programming. The textbook example is the “how many ways can I make change for you given these coins?” The number of ways to make change for a particular dollar value is not affected by the fact that you might have already given some change before. Also, keep in mind that you can almost always write dynamic programming using recursion with memoization which, in my opinion, makes the code easier to follow.
A recommended study plan
To conclude, here are my recommendations to prepare for a senior coding interview:
- Review the “big 5” data structures and solve some medium problems that use those data structures
- Practice a couple of medium dynamic programming problems
- Move on to the hard problems listed above where you will gain experience using less common data structures
- Finally, solve the “very hard” problems listed above to boost your confidence in your problem-solving ability
The harder problems take time, but the effort does pay off when you are in the interview.
Feel free to reach out if you have questions or want additional advice. If there’s enough interest, I will keep writing further blog posts on other interviewing modules, soft skills, and extra tricks to dazzle your interviewers.