Solving the LeetCode Puzzle: A Journey to Technical Proficiency.
A hands on blog on how to efficiently solve problems
Get into the basics of Problem Solving
Problem-solving is one of the most important attributes that one should master before moving on to any deep programming concept. Problem-solving gives one the thought process to analyze, visualize and see a real-world problem in terms of mathematics. No matter which branch it is, the basics are all about how well an intuition is defined over a problem. Problem-solving requires a unique mixture of creativity and logical thinking. The most fundamental way to get such a thought process and develop behind-the-scene thinking is coding a problem. It is done in such a way it divides a complex-looking problem into segments of understandable code dependencies (Basically creating functions wherever required to improve the readability). There is a way to approach a problem described below to solve any question that may be hard, medium or easy. This works on every single problem.
Pre-requisites
language(JAVA, C++, Python)
Basic maths
Working with conditional statements and loops
Functions and return types
default data structures: Arrays, Lists, Dictionaries, etc
Understanding the problem statement
One of the most common missteps when you're starting in coding is trying to tackle a problem all at once, without breaking it down into smaller, more manageable parts. It's kind of like trying to eat a whole pizza in one bite - not a great idea! Another common mistake is rushing into writing code without truly understanding what the problem is asking for. Before we dive into the world of coding, it's crucial to take a moment to understand the problem statement. This means figuring out the main components of the problem, the rules or limits, and the best tools (data structures and algorithms) for the job.
We'll break down problems step by step, similar to learning with building blocks. This approach boosts problem-solving skills, ensuring a clear plan for coding challenges, resulting in clean and functional code.
Solving and hands-on a problem
Count Asterisk this problem statement specifies that we will be given a String where every two consecutive vertical pairs of character '|' are grouped. In other words the 1st and 2nd '|' make a pair. The problem is to count the number of '*' (asterisks) between every such pair only.
Now let's try to visualize through the provided examples.
"l|*e*et|c**o|*de|" --> input String
"l|*e*et|c*o|\de|" --> Output integer: 2 (no of asterisks fulfilling the above conditions)
As shown above which substring(i.e. that occurs after every 2nd '|' and before 3rd '|') needs to be considered while computing the output.
My Thought Process and Intuition
Initially, there are some clues about the modulo in the question as we that there is a repetition of a loop over some time. just for now, we assume that we run it until we reach the last of the String. For this moment it is all about brute force the solution to get the basic code that can be modified into an optimised variant. As for now, we see for every 2nd '|' we start counting the number of '*' encountered. The code for the above follows:
class CountingAsterisk {
public static void main(String[] args) {
System.out.println(countAsterisks("iamprogrammer"));
}
public static int countAsterisks(String s) {
int count = 0;
int localCount = 0;
for (int i = 0; i < s.length(); i++) {
if (localCount % 2 == 0) {
if (s.charAt(i) == '*') {
count++;
}
}
if (s.charAt(i) == '|') {
localCount++;
}
}
return count;
}
}
Here we are using a count to count the no asterisks and a local count variable to count the number of '|' we encounter and whenever we reach a multiple it starts counting for the asterisk.
In the way most people solve problems, we don't start by writing code. Instead, it's like putting together pieces of a puzzle. We begin by figuring out what information we need (variables), then decide how to organize that information (data structure), identify if any concept of math that can be applied and finally, we handle special situations(edge cases) to make sure our solution works for all types of input. This step-by-step process helps us build a strong solution that we can then turn into actual code.
Optimization and Refactoring
Well after the brute force solution is written it's now time to research some new idea that costs less computer resources may it be memory/time (Optimization) or work on the same solution and do the same thing in a limited amount of lines of code(Refactoring). For some questions, it is already optimized like the above one, try to refactor it.
class CountingAsterisk {
public static void main(String[] args) {
System.out.println(countAsterisks("iamprogrammer"));
}
public int countAsterisks2(String s) {
int ans = 0;
int bars = 0;
for (final char c : s.toCharArray()) {
if (c == '|')
++bars;
else if (c == '*' && bars % 2 == 0)
++ans;
}
return ans;
}
}
now it is time for the code submission and to see your score.
Common mistakes
Once someone starts to code and deep dive into data structures and algorithms there are certain times that the pace of solving keeps on building until you have entered a problem that cracks your head and you give up. Most people give up problem-solving. The important thing is to either think from a different perspective or just google your problem or use AI to explain the problem statement and get some hints. This good practice allows us to tackle many annoying issues firsthand. It is mandatory thing not to give excess time to a specific problem that makes learning difficult, having a sneak peek into the solution isn't that half-bad sometimes it may be a healthy choice but, the important thing to remember is to come back to the same problem to solve it once again without looking at the solution. if it still fails then repeat the process over and over and at some time you will never forget the concept.
The Art of Consistency
Learning data structures and algorithms is all about how well and how frequently problems are solved. The Mix&Match approach works for many problems as well. Some problems are made to use more than one concept to work accordingly. Just like athletes who train consistently to enhance their performance, programmers solve problems regularly to strengthen their problem-solving "muscles." It's about making problem-solving a daily or weekly habit, whether through coding exercises, algorithmic puzzles, or real-world projects. Over time, this consistent practice leads to increased proficiency and adaptability, enabling programmers to tackle a wide range of tasks and continually evolve in their craft.
Conclusion
From tackling your first coding question to crafting solutions for real-world challenges, it's all about the thought process and problem-solving skills you've built. LeetCode is just the starting point in a vast field where developers continually innovate and refine solutions. The questions you've solved here offer a glimpse of how to approach problems before diving into code. Building a strong foundation in problem-solving is the key to success in the ever-evolving world of software development.