If you like the material here, why not buy me a coffee? I <3 coffee!
After doing over 200+ questions from EPI, CTCI and leetcode combined, I've hand selected questions I believe every software engineer needs to complete in preparation for the Big N whiteboarding interviews. These are questions, I believe will give the most bang for your buck and investment on time. Worthy of adding to your arsenal to fight the coding gods!
Each question has its own unique 'gotcha' that you should learn. You want to take each question to the most optimal solution in-order to fully maximize what you can learn from it. Some questions are onion questions, with multiple solutions to the problem, its also important to know them all. For example, do it both recursive and iteratively or BFS and DFS.
I am not an expert coder, nor do I call myself 'amazing' at coding. The example I provide, please use them with a grain of salt. I am a human just like you, we make mistakes. My code examples aren't flawless nor are they fully optimial. However, they are enough to pass interviews. So use them as such, just examples. You can always come up with something better than my code but that is not my intend with this repository. It is to show good enough code to pass Big N interviews, thats all.
Attempting to pass whiteboard interviews is a daunting task. No one is born natural to it. That is why I'd like to set a tone and mindset when I approach almost anything that I am unfamiliar with. Here are a few quick tips that can get you started.
You will fail. Accept it. However, DO NOT ALLOW it to dictate your future actions. There is only one effective way to deal with failure. That is to learn from it. Learn as much as you can from the choices you have made. In this case, that means, learn what you can from each question, encounter and process.
Even if you are prepared, you will have bad days and good days. Things that are out of your control will affect the decisions that other people make. Maybe they had a bad day too. The only thing that can land you the dream job is to try and to try many times. Increasing the chance of being hired with each session and use each session to improve upon what you already know. Only way is moving forward.
This is why this will lead up to my next point.
Yes you want that Big N job, we all want it. However, you cannot get that job unless you start shifting your objective from "winning" to "learning". "Winning" should never be your first objective, your first objective is to "learn". Why? For some, if "winning" was their first objective, they run into starter paralysis aka. fear. Afraid to lose. When "winning" or "losing" becomes your first priority, you become blinded from how the process can take you there. For others, people try to cheat the game by memorizing instead of ultimately learning which is by far more fundamentally sound for the lifespan of your career. Don't get me wrong, having a goal to win is important, but remember, its just a long term goal, not an obstacle.
Remember, there are limitless amount of questions someone can ask you, but that is because you can word it differently here and there but the process to get to the solution is similar if not the same as the next. That is why one should focus on learning patterns instead of trying to memorize or see as many questions. You must prepare for the inevitable scenario that you will have to solve a question you have never heard of it. In-order to tackle this, you must be able to identify patterns in the questions with previous questions you have faced and apply those solutions for this scenario. That is why you should focus on learning the coding patterns and techniques.
Everyone has different levels of thinking. When I first started, I had trouble even thinking about the how and what DS and Algo to use. After a while, I was able to get optimized theorical solutions but I was lacking in the implementation department. When it came time to write code, I would stumble a lot. Trying to put my words and thought process into code was difficult for me.
It will be different for you, but I 100% recommend, make sure you run through your 'theorical' solution a few times with a couple edge cases. Ascending, descending, empty list, duplicates, even, odd etc... I've had tons of scenarios where I would implement my solution to find out I forgot an important missing piece.
So read the question twice, three times, make sure you don't miss anything and PLAN! Make sure you spend ATLEAST 10 minutes before you write any code, DRAW IT OUT, TALK IT OUT. I had to draw pictures, my techinique was to draw it and follow with the drawing as I coded. It was the only way I was able to get consistent results. For some questions, I had to use real world objects because I could relate to them easily to find edge cases. Like questions that deal with swapping, I would immediately visualize a theater row of seats. If the question also wanted to pair things together, I would think of boyfriend/girlfriends all randomly seated and your job was to pair the couples together. I know it's wierd, but it worked for me. Find your method, test a few ways and make sure it works for you.
These are the usual stages people are in:
- Stage 1: I can't even think of any solution!
- Stage 2: I can think of a solution but its not optimal.
- Stage 3: I can think of the optimal solution but I can't implement my idea correctly.
- Stage 4: I can implement my idea correctly but not within 20-30 mins.
- Stage 5: I've ascended!
It is important that you struggle with questions. This struggling will allow you to see why your current way of thinking is incorrect. This way, when the solution is given to you, you can figure out the difference between the ideal and your method. You must be open to new approaches and methods that are foreign to you. When I first started, I approached problems radically different than I do know. My past solutions were very wonky and unconcise. Multiple problems with the use of the language, structure, dead complex code and naming of variables/functions. It made it very hard for someone else to read. I have since refined my code to be as dumb proof as I can do while being very simple. Take the time to refine your solutions by comparing what others have done.
When you at work or in school, doing chores, driving, or whatever. Have one or two questions you are struggling with think about them during down times. This way your brain is on a constant problem solving mode that you can understand how you think.
Prior to writing or testing your code. The question may come with an example that might be too big of a test case. If the example has 10 items in an array, dilute it to 3 or 4 to run your test cases. If the questions happens to deal with 2d arrays, use a 2x2 or 3x3 array as your test case. If the question deals with a list of strings, use simple one or two character words like, [aa, bb, cc] or [a,b,c]. In any case, always try to dilute the question by using simple and easy to test examples to help you avoid dealing with ambiguous test examples. This will also allow you to wrap your head around the question quicker by using this approach.
If you come across a question that you greatly struggle with and had to look up the solution, or your solution to a question was slow or unconcise. Try to redo this question in a few weeks. This will again help you figure out what else you are still missing to learn from the question. You can also select another question in a similar category with the question you were struggling with.
This is more of a method of practicing. Similar to how atheletes trains with ankle weights for their upcoming race. If the average interview expects you to finish a question in 45 mins, finish it in 30 mins. If you expect to do 2-3 hours of interviews in a row, do 5 in row. Do 10 easy questions in a row and finish each of them within 20 mins. By setting the bar higher, if you don't make the bar, you atleast land halfway decently. Again the objective is to not meet each of these expectations 100%, it is to see where your limit is. If you do this correctly, you will actually fail everytime. It is meant to judge how prepared you are. Its like going to the gym and doing reps until failure.
If I were to say which part was the more important step from this entire post. I would pick this one here. Mock interviews are EXTREMELY IMPORTANT! Did you hear me? EXTREMELY IMPORTANT! I highly recommend you find another person who is in a similar situation like you, both in skill level and dedication. This step requires some dedication and sticking to a schedule. Both of you should agree to meet up a few times a week to practice interviews. For example, I found mine on pramp, both us would try to solve a question then when we would meet up using google hangouts and google docs, we would ask each other the question we just solved. As you do this a couple times, you understand the areas of each other weakness and provide feedback. You can sometimes learn some new way of approaching problems from each other. Its a great and important learning step to have instant feedback on your performance. We use to do marathon mock interviews to over prepare. Like give each other 5 questions in a row and try to solve them as quickly as possible. Our sessions would usually last around 3 hours. So again, this step really only works if you can find someone willing to put in the time and effort just like you would. So use websites like pramp to start mock interviews and as you go ask if they are willing to do this type of preparation.
Understand that the interviewer is trying to find signals during the interview. If he cannot 100% assess whether you know your stuff, then you will not get the role. What that means is, DO NOT go through your interview/question without explaining your thought process. You can fail the interview even if you get the question 100% correct when you speak nothing. The only thing it shows is that you may have been given a question you have seen before and memorized the solution. It is better if you can solve the question in buckets, break down the question piece by piece and question the pros and cons of your approach and your other approaches.
I've had situations where I did not get the code 100% working, but because I questioned by code, found errors in my approach, fixed them, tried some test cases, refactored, and broken down my code into easily testable chunks, I passed the interview. The interviewer can easily understand my approach to programming in the real environment.
You will need to learn to talk while you code, even if its not what you normally do. If you are stuck, say so and on what, that way the interview can possibility help you out or question something. If you don't say a word, the interview does not know if you are just thinking or really stuck.
The idea of wishful programming is to assume you already have a given method, value, something that can help you solve a subset of your given problem. The issue with a lot of people when they think about problems, is that, they think of too many details. If given a very complex problem with multiple requirements, its hard to figure out where to start. I love to apply wishful programming into my thought process and my solution. It can help break down a problem and identify subproblems, while keeping you code clean and bug free. You will also noticed that your code will become more testable as well as more maintainable and malleable since this thinking forces you to think in a dependecy injection like way. You can see plenty of examples of wishful programming taking place in this repo, so look around.
There is also an important aspect of this thinking. With wishful programming, you are making an attempt to abstract details away from the user. That means, when a user uses your api, all they care about is getting the correct result they want, NOT about how you got to that result. So if this is applied in every level of your code, as you dig deeper into each method, from the current method's perspective, what does the method only care about?
First start at a top-down approach and a very high level understanding of the problem. Along the way to your solution, just create a method as a placeholder for calculating a certain sub-problem. Maybe you don't remember how this was implemented, thats OK, write a placeholder method and come back to it later. Maybe you have to do some pre-processing or filtering on a given collection before you can begin solving the meat of the problem. It's perfectly fine to sub a method into it and come back to it.
Make sure your focus is to create a skeleton working layout of your solution using your placeholder methods during your first pass with the problem. Once that layout is set, you can worry about the little bitty details then. But during your first pass, just wave your hand and assume you have it provided to you and continue on.
- Elements of Programming Interviews
- Cracking the Coding Interview
- https://leetcode.com/
- Head first into Design Patterns
- https://www.pramp.com/
- https://interviewing.io/
Assuming you are starting from ground zero, no idea about Algos and Data Structures. First read CTCI's chapters, for each chapter, you can attempt to do a few questions until you hit a wall. Don't try to understand every chapter fully, you should figure out the scope and breath of knowledge you need to know by reading each chapter. After reading each chapter, tackle a chapter you "think" you can accomplish in a week. Use that entire week to purely focus on a specific category. For example, I suck at heaps, so I do a bunch of questions on heaps for a week. Then switch to recursion for a week, then graphs then back to heaps again. Every other week you revisit a topic to test whether or not you truely understand that topic or not. Over time it will get easier.
I recommend doing at least 200 questions and several mock interviews before you begin your phone screens. Do the top 100 liked easy questions and the top 100 liked medium questions found on leetcode. Then cherry pick some of the most common hard questions. At this point you should be ready to begin your phone screens.
A good benchmark to be able to answer most of the easy questions in 10-20 mins and the medium questions in 20-30 mins. You should be able to one-click success the solutions 90% of the easy and medium questions. If after 200+ questions you are not able to do this, this means you are putting quantity over quality. Repeat your questions, understand the fundamentals, don't try new questions until you can hit this benchmark consistently.
This should give you a month or two left to squeeze in any other questions found in EOPI or CTCI in preparation for on-site. The next 100 questions should be done on paper or the white-board. Start looking at the honors section of EOPI but majority of your focus should now be 30% easy, 50% medium, 20% hard. Similar to the first 200 questions, one-click sucesss 90% of the time. At the end of everything, you should have done a total of 300+ questions between leetcode and the two books.
Depending on your role, system design will need to be sprinkled in during your studies. Use mock interviews to gauge how much system design you need left to study.
Rank your companies in tiers from 1,2,3.
- Tier 1 - I would join them if I got an offer instantly.
- Tier 2 - I would join them if it was right for me.
- Tier 3 - I would join them if I was desperate.
Tier 3 would most obviously be your practice rounds. You can apply to all tiers then schedule them in sections. For example, schedule Tier 3 interviews in mid-June, then Tier 2 interviews in early-July, then Tier 1 interviews in late-July. If you were to get any offer in a higher tier, it would more or less mean you would accept that over any lower tier offers.