How to Develop Your Own Toolbox for Solving Coding Problems

When you’re studying, don’t just look at somebody’s solution and just type it in. You see that it runs and you just move on to the next thing. You will not learn anything by just typing in somebody else’s solution you found online. You don’t know the reasoning behind why they solved the problem that way.

When to Start Solving Coding Problems

The problem solving aspect comes once you have acquired the prerequisite knowledge. By creating models of the problem domain, we are able to utilize a better and more efficient problem solving process. These models allow us to describe the data that our algorithms will manipulate in a much more consistent way with respect to the problem itself.

Make an Attempt to Solve the Problem

Look at a coding problem and see if you can solve it without looking at any solution. This means you’re creating obstacles for yourself and you’re trying to push beyond your current skill boundary. The success is beyond your current skill level. You must tackle your obstacles head on.

During the first attempt to solve a problem, your goal is not to immediately figure out the correct answer. The real purpose of the first attempt is to:

  • Think and gain a deeper understanding of the topics you studied earlier.
  • Learn as many new problem solving techniques as you can.
  • Develop your own toolbox for solving problems.

There is no substitute for your ability to think in a systematic way. But you can refine your thinking process by asking yourself the questions:

  • Was the problem statement clear to you when you read it?
  • What did you think of doing first?
  • Were you reminded of a construct in general or a general structure of solution that you thought would be useful?
  • Have you previously seen problems that resemble this one?
  • Did you feel stuck at any point while working on this problem? Read What to do when you get stuck.
  • What did you choose as your test case?
  • Do you think you’ve covered all possible scenarios with your tests?
  • What program design techniques did you apply to solve this problem?
  • Are there any constructs of the programming language that you find difficult or confusing to use?
  • What issues make programming constructs difficult to use? For example, the keyword used, the syntax, the examples, the documentation for the construct, etc.

Timebox your attempt to one hour. If you exceed your time limit, refer to the solution. Read the code. Understand the reasoning behind them.

Come Up with Questions

Write down your questions if you are confused about the solution. Asking good questions is a skill and it can only be honed if you take time to think about your problem areas.

Ask yourself the questions:

  • What are the obstacles in front of you that you need to address?
  • Did you understand the concept?
  • Are you having difficulty applying the concept?
  • Are you able to pick the right data structure for a given problem?
  • Are you having difficulty picking the right algorithm?
  • Do you know which problem solving technique to apply for this problem?
  • Where exactly are you having difficulty solving the problem?

Develop the skills to translate high-level descriptions into working code in your favorite programming language. There is no substitute for the detailed understanding of an algorithm that comes from providing your own working implementation of it.

You have to write down the answers to these questions:

  • Why did you fail?
  • What mistakes did you make?

As long as you fail in new ways, you’ll grow smarter and more informed each time. Rather than torturing yourself for what you might have done differently, use that immediate flash of insight to improve and adapt your strategy. This will help you overcome your obstacles.

Choosing the Right Data Structure

Data structures are used in almost every program, so knowing when and how to use them is an essential skill for a skilled programmer. The purpose of a data structure is to organize data so you can access it quickly.

One of the basic techniques for improving algorithms is to structure the data in such a way that the resulting operations can be efficiently carried out. You must be familiar with stack, queue, set, tree, graph, heap and hashing.

The queue data structure, used in implementation of breadth-first search, sequentially organizes data so that removing an object from the front or adding an object to the back takes constant time.

The stack data structure, which is crucial in iterative implementation of depth-first search, lets you remove an object from or add an object to the front in constant time.

  • What are the pros and cons of different data structures?
  • How should you choose which one to use in a program?

In general, the more operations a data structure supports, the slower the operations and the greater the space overhead.

When implementing a program, it’s important that you think carefully about exactly which operations you’ll use over and over again. For example, do you care only about tracking which objects are stored in a data structure, or do you also want them ordered in a specific way?

Once you understand your program’s needs, you can follow the principle of parsimony and choose a data structure that supports all the desired operations and no superfluous ones

Building Your Problem Solving Skills

You are building your problem solving skills as you go along. These problems are hurdles that you have to go over in order to build your skills. If you’re not able to solve a problem, it means you have to go beyond your current skill level.

That’s why you keep repeating this process so it becomes part of you and you start recognizing the things that you’ve done in the past. You know the reason why you were not able to do it, then you address the gaps in your knowledge. You will study to fill those gaps. Your study time becomes efficient because you’re addressing only your problem areas.

Problem Solving Strategies

There are only a handful of problem solving strategies.

  • [Divide and Conquer]({% post_url 2019-04-04-divide-and-conquer %})
  • [Dynamic Programming]({% post_url 2019-04-18-dynamic-programming %})
  • [Backtracking]({% post_url 2019-04-25-backtracking %})
  • [Greedy Method]({% post_url 2019-04-11-greedy-method %})
  • Branch and Bound
  • Basic Search and Traversal Techniques

You’re going to acquire these tools over time. Your skill is going to grow over time. Are you clear on how to go about solving a problem, knowing these problem solving techniques?

Making the right high level decisions of the solution before you start coding is critical to avoiding reworking your code in the middle of the interview. This means you will be able to come up with optimal solution within 45 minutes. This is a top down approach to aid you in your assimilation process.

Solution Comparison

You also learn by reading the code written by others. Compare your solutions with others. Think about the following:

  • What differences do you notice between the solutions?
  • Identify the strengths and weaknesses in each of the solutions.
  • Given these solutions, which of these do you prefer and why?
  • Is there a solution you find confusing or hard to understand?

These are some questions to guide you in your thinking process. Feel free to add your own questions to this list.

Compare different solutions, deeply understand them and jot down observations in your notes. You can then move on to solving that coding problem and then look at the solved solution in a textbook.

When you’re looking at the solution, there is no way that you can just solve for the very first time and come up with the perfect solution. But when you compare your solution with the textbook, then you start to see, why they made this decision versus what you have decided. You start noticing all the differences. You need to find answers to these questions and jot them down in your notes.

Followup Questions

Prepare for most of the follow-up questions. For example, when refining your solution, ask:

  • Did I cover all types of test cases?
  • What is the time and space complexity?
  • Is the input size too large?
  • Can I save the intermediate results in an array/matrix/list to decrease space utilization?
  • How do I deal with multiple machines running in parallel?

Approaching the Problem

For a given problem:

  • Understand the problem statement.
  • Tackle it from different angles.
  • Solve on paper.
  • Test your solution.
  • Compare your solution with optimized answers.
  • Analyse your solution to further improve its space and time complexity.
  • Reflect

You must learn to solve problems on your own. This will build the skills to solve problems you’ve never seen before in interviews. You’re going to gain confidence over time.

Focus on Quality of Work

Instead of focusing on the number of problems you can solve, focus on the quality of work that you are doing while solving each problem. Over time, the number of problems you can solve will go up.

Follow these steps to achieve quality work:

  • Make sure you have deeply understood the techniques you used to solve the problem.
  • Identify the techniques used in solutions from others as well as your solution.
  • Find the correlation between problems and summarize a standardized solution for all similar problems.
  • Keep track of where you made mistakes and why you made them.
  • How can you prevent these mistakes in the future?
  • Prepare answers for followup questions.
  • Challenge yourself to see where you can improve.

Take time to understand the solution as much as possible, take notes and review your notes everyday.

Take Notes

Think with pen and paper. Write down your thoughts. Analyze your choice of data structure and algorithms. You are thinking about your technical decisions and making recall easier later when you need it.

According to research in the Developmental Science Journal, the best way to learn something is to write it out on paper. Handwriting activates large regions of the brain responsible for thinking, language, healing and working memory.

You’re organizing your thoughts when taking notes. Your notes help you to organize your knowledge in a way that is easier for you to remember.

The study time will be much shorter with your notes. Understanding your own thought process takes far less time than understanding other people’s solutions. Only you can determine where you got stuck in the past and where you need to focus more of your attention.

If you have your own notes, reviewing your notes is the best way to prepare for the next time you have an interview. Because it’s going to compress the study time you need to brush up on these topics. If your notes become blog posts, you can review your own blog posts. Now you can sharpen your thinking process by reviewing your study notes with insights.

Refine Your Thinking Skill

Thinking skills is a prerequisite to problem solving skills. You have to write down your questions because your ability to ask good questions is a skill. When you come up with a good question, you have taken time to think, you are able to identify something that is not clear to you. You have to write it down.

For instance, I don’t understand why this data structure was chosen for this problem. I don’t know why they’re shifting elements from the end of the array instead of the beginning of the array.

These questions lie within the fuzzy area of your mind. If you don’t think through these issues and don’t write them down, it becomes gaps in your knowledge. When you try to apply your knowledge, you will struggle to solve problems. Only if you have a good and deep understanding of the concepts, you’ll be ready to move on to the next step which is applying that knowledge to start writing code.

First Principles Thinking

Practice of taking any idea, any concept and then stripping it back to basic, fundamental building blocks that are incontestable, free of subjective bias and can be universally accepted as facts.

You do this by questioning every assumption you think you know about a given problem or scenario and challenging current knowledge that is learned, but not essential and doing this over and over until you get to its most basic roots. You will be able to:

  • Think inventively.
  • Invent new solutions to old problems.
  • Change trajectory of creating from iterating on existing thinking to one of genuine innovation.
  • Retain and use knowledge effectively because you understand the fundamental building blocks.

For example, you see a problem represented as a graph. Do we really need a graph to solve the problem? What are the alternative representations that we can use to solve the problem? If you apply First Principles Thinking you will be able to challenge the current knowledge and invent new solutions to old problems.

Reflection and Review

It is natural to rush into solving as many practice problems as possible to meet the preparation deadline. This can be stressful, especially when there are many topics to learn. Take time to reflect on the solution. It’s wise to slow down and reflect.

If you skip reflection, you will feel more overwhelmed as you progress. Because, you will forget things you have already learned. Reflection is a way to deepen your understanding of the material.

It can also uncover your mistakes, so you can fill in the gaps in your knowledge. Most of the time, you don’t have to memorize anything if you understand the concept really well. If you have to memorize something, the secret is to use spaced repetition.

After solving the problem, take five to ten minutes to reflect on the solution. Any solution can be improved.

  • How can I improve it?
  • What could I have done differently?
  • Why does this solution work?
  • Why does it not work?
  • What are the trade offs I could make?

And as you go review your notes, every few days you’re going to start noticing certain patterns. And you will develop insights from your own notes. Review your notes as the first thing in the morning before you jump into any new material. Constantly brush up on your old notes before moving on to the next topic. Write a blog post to organize your thinking process.