I am a 3rd year CSE student, and like many software engineers to be, I have been grinding Data Structures and Algorithms for quite some time now. This post is not a flex of how many problems I do everyday, but a sincere account of what went wrong and what went right for me, and my suggestions for a better DSA grind.
You might be facing problems similar to me, and may find some things here useful.
My biggest misconception when I started DSA
When I first started learning algorithms, I thought that the number of problems I do has a direct relationship with my ability to solve problems.
As a result, I kept a count of how many problems I did everyday, and was quite proud of myself when I solved 8+ problems in a day.
My biggest lesson was that I have to care less about the number of problems I solve, and more about how many of those problems I can actually reproduce from memory.
I realized this when I couldn't remember how to implement a simple level order traversal weeks after I learned it.
The way I learned to approach DSA
Instead of thinking of DSA as hundreds of unique problems, I thought of it as patterns repeated in different problems and tried to understand these patterns.
Some of these patterns are:
• sliding window (fixed and variable)
• two pointers
• fast and slow pointers
• binary search on the answer
• kadane's algorithm
• recursion -> memoization -> tabluation ladder for DP
• BFS / DFS templates for trees and graphs
By learning these patterns and learning how to recognize which pattern to apply for a problem, the problem becomes much easier.
Instead of thinking "how can I solve this problem", I think "what pattern can I apply to this problem".
While I used to aim for 500+ problems, my new goal is to know all patterns in DSA so well that I can solve any new problem thrown at me.
This is what DSA interviews primarily test for: your ability to solve new problems.
How I increased retention of previously learned concepts
One thing I've learned the hard way is that the way you revise is much more important than how much you study. I used to revise by re-reading my old code and thought that I retained a lot by doing so, but I didn't realize that I wasn't generating any new memories, I was merely recognizing something I already knew.
Instead, I do the following to revise:
- Open a problem
- Try to solve it without hints or looking at my old code
- Once I've tried my best, look at the solution
- Once I've understood the solution, close the solution and try to write the code from scratch again
You'll notice that steps 2 and 3 are all about struggling with the problem before getting help. This is essential to generating solid long-term memories.
When you try your hardest and you still can't solve a problem, looking at a solution and understanding it feels really good because you've achieved mastery over this topic.
However, once the solution is in front of you, it's easy to recognize, and the recognition gives you a false sense of retention. This is why you have to struggle before looking at the solution.
The revision system I follow
One thing I've had to learn for my DSA grind is an effective system of revision. The following is the system I've come up with:
I color code the problems based on how well I did during my initial struggle (step 2):
- 🔴: I blanked out or needed help. I revise this problem in 3-4 days, then about a week later, and finally after about 3 weeks
- 🟡: I was able to solve it, but struggled or took a while. I revise this problem after about a week
- 🟢: I solved the problem quickly and with no help. I quickly scan through this problem after some time has passed, but don't need to revise the code again
The idea is that I can only mark a problem as 🟢 if I can solve it with no help or struggle. If I needed hints during the initial solving, I have to mark it as 🔴. It can be tempting to mark many problems as 🟢, but it's important to be honest with yourself.
The spacing is also important. Instead of having a revision session on a Sunday after a week of no coding, you space out your revision by having a small revision session everyday before doing new problems.
It's better to revise a little bit everyday than to cram in a big revision session on a weekend. The reason for this is that you want to avoid massed practice and encourage spaced practice.
Spaced practice has proven to be much more effective at generating long-term memories. While you might feel like you retained more information by cramming, studies show that people who utilize spaced practice do significantly better when tested than their counterparts.
Choosing a language to implement my solutions in
I was really conflicted about the language to implement my solutions in. While most people do DSA in C++, most tutorial videos online are in C++ as well. Additionally, I felt like interviewers would penalize me if they found someone using Python over C++. Here's what I've come to realize:
DSA concepts are language-agnostic. It's easy to switch between languages if you know the general idea of an algorithm.
That's why I prefer Python for my own practice: it's easier to write and read, and saves me time during the implementation phase. Most of the concepts taught in DSA are the same, regardless of the language they're implemented in.
I watch videos and tutorials in C++ and implement what I learn in Python, and I think this system works well.
Most companies also allow you to interview in any mainstream language, and writing code in Python will allow me to write shorter, neater code under time constraints, compared to C++.
Additionally, if I ever decide to move to competitive programming and need to learn C++, I can rely on my knowledge of patterns and concepts to learn the language faster.
Bugs that haunt you
I have a page in my notebook dedicated to recurring bugs.
There are certain bugs that I tend to make over and over again, and I've found that it's extremely important to keep track of them in one place.
For example, I often make the following mistakes:
• using a node object instead of node.val
• forgetting to capture the return value of a recursive function
• updating a value and using the updated value in the same expression where I should be using the old value
• using [[]] ] n to create a 2D array, which causes all rows to reference the same list
Once you start learning about your recurring bugs, it's essential to recognize when and why you make them.
Keeping track of bugs is a great way to monitor your progress as well, since you'll eventually realize your bug count decreases as your DSA ability improves.
Thoughts to someone who is just starting out
I think it's really important to build depth, rather than width. It's always better to know 250 problems you can reproduce from memory, rather than 1000 problems you only half-remember.
It's important to revise everyday, and if possible, every time you study a new topic. Try to avoid looking at solutions or old code right away and give yourself time to struggle.
I think it's very important to learn patterns instead of trying to memorize individual problems. New problems should be variations on old patterns, and recognizing the pattern in a problem allows you to solve it easily.
It's crucial to keep track of recurring bugs. By doing this, you can see patterns in the bugs you make, which helps you identify your weak areas in DSA.
The worst thing to do is to compare yourself to others. Everyone has their own way of learning DSA, and trying to replicate someone else's strategy rarely works. I think it's important to develop your own system of learning, and to be consistent with it.
Where am I now?
I am still at the beginning of my journey, but I've studied enough patterns to have a good grasp on the basics of DSA. I've built a strong foundation on arrays, binary search, linked lists, stacks, heaps, binary trees, graphs, greedy algorithms, and dynamic programming. Now, I'm moving on to more advanced topics in dynamic programming and graphs, such as advanced DP and Union-Find, which are new to me.
Sometimes when I study a topic, I feel like I've forgotten something I knew earlier. I've come to accept that this is a part of the learning process, and I'll get back to that topic later with better retention.
Like I said earlier, learning DSA is a marathon, not a sprint. If you want to go far, pace yourself and revise often. Good luck, and see you on the grind!
Top comments (0)