Every solution starts with a strategy, and an algorithm is a strategy for solving the coding problem. So programmers must learn to design an efficient algorithm and translate this “algorithm” into the correct code to get the job done.
But there are many coding problems available in data structure and algorithms, and most of the time, these problems are new to us. So as a programmer, we need to develop ourselves as confident problem solvers who are not intimidated by the difficulty of the given problem. Our long-term goal should be simple: learn to design correct and efficient code in a given time. As we practice more and more, we will have more experience in problem-solving and our work will be easy. Here are some essential skills which we should practice for every coding problem:
Now the critical question would be: is there some well-defined guided strategy to approach and solve a coding problem? If yes, then what are the critical steps? Let’s think and explore!
Solving a problem requires a clear understanding of the problem. Unfortunately, sometimes we read the first few lines and assume the remaining part of the problem. Or sometimes, we ignore this step because of something similar we have seen in the past. We should believe these as an unfair practice and develop a clear approach to problem understanding.
During problem solving, every small detail can help us to design an efficient solution. Sometimes a tiny change in the question may change the solution approach. Taking short extra time in problem understanding will give us more confidence later. The fact is: we never want to find out halfway through that we misunderstood the problem.
It doesn’t matter if we have gone through a question in the past or not: we should read the question several times. So take a paper and write down everything while going through the problem. Exploring through some examples will also help us clarify how many cases our algorithm can handle and the possible input-output patterns. We should also explore the scenario for large input, edge cases, and invalid input. Sometimes it’s pretty common for a problem description to suffer from these types of deficiency:
These deficiencies may be due to the abstract explanation of the problem description in our natural languages. So it’s our responsibility to identify such deficiency and work with the interviewer or problem provider to clarify it. We should start by seeking answers to the following questions:
The best approach would be to think of a correct solution that comes immediately into our thought. It does not matter even it is in an inefficient approach i.e. having a correct and inefficient answer is much better than an incorrect solution or significant delay in the solution. This could help us in so many ways:
Here are some examples of brute force patterns: three nested loops, two nested loops, solution using extra memory, solution using sorting, double traversal in the binary tree, considering all sub-array or substrings, exhaustive search, etc.
After thinking and communicating the brute force idea, the interviewer may ask for its time and space complexity. We need to work on paper, analyse each critical operation and write in the form of Big-O notation. A clear conceptual idea of time and space complexity analysis is essential at this stage. A good practice of various code pattern analysis (iterative, recursive, etc.) would help a lot.
This is a stage to use the best experience of problem-solving and apply various problem-solving strategies. One practical truth is: moving from a basic algorithm to the most efficient algorithm is a little difficult in a single step. Each time, we need to optimize the previous algorithm and stop when there is no further optimization possible. Revisiting the problem description and looking for some additional information can help a lot in further optimization. For example:
The idea would be simple: we should learn the use case of efficient problem-solving patterns on various data structures. Continuously thinking, analyzing, and looking for a better solution is the core idea.
Here are some best examples of problems where several levels of optimisations are feasible. Practicing such types of coding questions helps a lot in building confidence.
Before you jump into the end-to-end code implementation, it’s good practice to write pseudocode on paper. It would be helpful in defining code structure and critical operations. Some programmers skip this step, but writing the final code becomes easier when we have well-designed pseudocode.
Simplifying and optimizing the code may require a few iterations of observation. We need to ask these questions once we are done writing the code:
Enjoy learning, Enjoy coding, Enjoy algorithms!
Get well-designed application and interview centirc content on ds-algorithms, machine learning, system design and oops. Content will be delivered weekly.