Life is a rollercoaster, and we never know what lies ahead. But it’s the thrill of the unknown that makes the ride worthwhile.
After a not-so-good Week 2, I still managed to keep this streak alive. There were moments when I questioned myself: Is this worth it? Are these small steps really going to make a difference?
The only way to find out is by working on these things patiently and giving them time to fall into place. This week, I focused on recursion concepts and linked list concepts. While challenges persisted, I embraced the process and stayed consistent.Each small victory reminded me that growth happens in the details, and these steps—no matter how small—are building the foundation for something bigger.
Recursion: Solving Problems One Call at a Time (Literally)
Recursion is a concept where a function calls itself to solve smaller instances of the same problem—kind of like asking yourself, “Did I lock the door?” and then revisiting it again and again to make sure.
At its core, recursion is about breaking down complex problems into bite-sized pieces and solving them step by step. What makes recursion fascinating is that it often requires fewer lines of code to solve a problem, but it demands more thought and logic to get it right. It’s the ultimate trade-off: simplicity in syntax but complexity in understanding.
Every recursion needs two key ingredients:
A base case: The moment you finally stop checking if the door is locked (or, in coding terms, when the function stops calling itself).
A recursive case: The part where the function continues working on smaller chunks, just like that nagging thought that sends you back to double-check.
While it might seem a little overwhelming at first, recursion is one of the most elegant ways to tackle problems involving repetitive patterns or hierarchical structures. Once you get the hang of it, it’s both fun and satisfying—just like solving a puzzle!
The first problem I tackled in recursion was the Rope Cutting Problem. Given the length of a rope (n) and three possible lengths (a, b, c), the task was to divide the rope into the maximum number of pieces, using these lengths in any order.
The trick? Keep calling the function recursively, subtracting n by a, b, or c at each step, until the rope is fully divided. This problem showed me how recursion can break a problem into smaller chunks while testing all possibilities to find the optimal solution.
Next, I moved on to the Substring Problem, where the goal was to generate all possible substrings of a given string. While I had solved this earlier using bit magic (shoutout to Week 1!), this time I approached it with recursion.
The magical part? Start with an empty string and make two recursive calls at every step:
Include the current character in the substring.
Exclude the current character.
By the time the recursion completes, you’ll have all possible substrings—simple yet incredibly powerful. This problem reinforced how recursion can elegantly explore every possibility with minimal code!
Then came the Subset Sum Problem. The task? Find the number of subsets in an array that add up to a specific target sum. Initially, I thought iteratively, adding elements directly to check combinations. But recursion offered a more dynamic approach.
At every step, I made two recursive calls:
Include the current element by subtracting it from the target sum.
Exclude the current element and move to the next.
The base case checked if the target sum equaled zero, meaning a valid subset was found. This problem really opened my eyes to how recursion can handle combinatorial tasks effortlessly, eliminating the need for explicit loops.
Another interesting challenge was generating all permutations of a string. At first, it felt a bit overwhelming—how do you systematically arrange every possible combination? But recursion came to the rescue.
Here’s what clicked for me:
I swapped the current character with each character in the string, one by one.
Then, I let recursion take over to repeat the process for the rest of the string.
The magic happens when the current position (n) equals the length of the string, and voilà—a full permutation is formed!
This problem felt like solving a puzzle, with recursion guiding me through every possible arrangement. It was both a challenge and a reminder of how powerful a simple approach can be.
The Tower of Hanoi
Now let’s talk about a mind-blowing problem: the Tower of Hanoi. This classic puzzle wasn’t just about moving disks; it was about understanding and following some really clever rules.
The challenge? Transfer all the disks from Tower A to Tower C, using Tower B as an intermediate. The catch? You can only move one disk at a time, and a larger disk can never sit on top of a smaller one.
At first, it felt daunting—it’s one of those problems that really tests your logical thinking. The key insight here is to break the problem down recursively:
First, transfer the top n-1 disks from Tower A to Tower B, using Tower C as the intermediate.
Then, move the largest disk directly from Tower A to Tower C.
Finally, transfer the n-1 disks from Tower B to Tower C, with Tower A as the intermediate.
It’s a problem where recursion truly shines. Each move is part of a larger strategy, and the elegance of the solution lies in how the smaller problems (moving n-1 disks) come together to solve the big one.
The Tower of Hanoi isn’t just a puzzle—it’s a masterclass in breaking down complex tasks into manageable steps. It left me amazed at how recursion can turn seemingly impossible tasks into structured and solvable problems!
Linked Lists: Chaining Data with Nodes
Last week, I didn’t get to solve a lot of problems in linked lists, but the ones I did solve were truly insightful.
One of the first concepts I tackled in linked lists was the Floyd’s Cycle Detection Algorithm. At first glance, the idea of detecting a loop in a linked list seemed tricky, but this algorithm made it surprisingly intuitive.
The key players here are the fast and slow pointers, and they quickly became my favorites for solving such problems. The logic is simple yet brilliant:
The slow pointer takes it slow, moving one step at a time.
The fast pointer, as the name suggests, zips ahead two steps at a time.
If there’s a loop, the fast pointer will eventually catch up and meet the slow pointer—proof that a cycle exists in the list.
When I first implemented this, it felt like magic watching these two pointers reveal the cycle. It’s one of those algorithms that’s elegant, efficient, and incredibly satisfying to understand and execute.
After grasping Floyd’s Cycle Detection Algorithm, I wanted to take things a step further and learn how to remove a loop if one exists. It was an exciting extension to the problem, as it required me not only to detect the cycle but also to break it.
Here’s how I approached it:
First, I applied Floyd’s Cycle Detection Algorithm to check for a loop. When the fast and slow pointers met, I knew there was a cycle.
Next, I reset the slow pointer to the head of the list while keeping the fast pointer at the meeting point.
I moved both pointers one step at a time, and kept going until their next pointers were the same.
Once they matched, I knew I’d found the start of the loop, so I just set the next pointer of the fast pointer to NULL, effectively breaking the cycle.
It was like solving a puzzle, and honestly, the moment I broke the loop, it felt incredibly rewarding.
Conclusion
As Week 3 comes to a close, I can’t help but feel a sense of accomplishment, even though it wasn’t all smooth sailing. There were times I doubted if my small steps were making any difference, but as I worked through the problems, I realized how crucial each piece of knowledge is in building a stronger foundation.
From recursion to linked lists, this week reinforced my belief in the power of consistency. It’s not always about solving every problem perfectly; it’s about sticking with it and gradually piecing everything together. Each new concept—whether it was Floyd’s Cycle Detection or solving the Tower of Hanoi—felt like unlocking a new level of understanding.
So, here’s to staying patient and letting these concepts fall into place, one problem at a time! Week 3 might not have been perfect, but the progress I made was real, and that’s what counts.
If you are curious about what problems have I solved then here’s a list for you:
Rope Cutting Problem
Substring Generation
Subset Sum Problem
Permutations of a String
Tower of Hanoi
Josephus Problem
Floyd's Cycle Detection Algorithm
Removing Loop in Linked List
Intersection of Two Linked Lists