Working Through Algorithmic Puzzles With Python
I spent several weeks going through the puzzles in Data Structure And Algorithmic Thinking With Python Data Structure And Algorithmic Puzzles last year. The book is useful if you are trying to build actual problem-solving ability rather than just memorizing sorting algorithms. It covers the ground most beginners miss when they only work through LeetCode-style questions. The puzzles are structured around real thinking patterns instead of pattern-matching templates. The first thing you will notice is that the puzzles don't give you the algorithm upfront. You have to derive it. That is the whole point. I ran into this with puzzle 34, which involves finding a duplicate in an array where every element appears exactly twice except one. The obvious approach is a hash set, but the puzzle is designed to make you think about bit manipulation. Using XOR to cancel out pairs gets you down to O(1) space. Most people stop at the hash set solution and move on. The book expects you to push further. I remember struggling with a puzzle that asked for the longest consecutive sequence in an unsorted array. My first attempt used sorting, which gave O(n log n) time. Then I tried a union-find approach because I had read about it somewhere. It worked but was overcomplicated. The actual intended solution uses a hash set for O(n) lookups with a clever trick: you only start traversing from the smallest element of any potential sequence. This avoids redundant work and keeps the overall complexity linear. I wasted about three hours on that one before I just looked at the answer and understood why my approaches were wrong.
Getting Started With The Book
The book is available for purchase on Amazon and other major retailers. It has been published as an open-access resource as well, so you can find PDF versions through academic and open-source channels. The puzzles are organized by difficulty and topic, covering data structures like arrays, linked lists, trees, graphs, and hash tables, then moving into algorithms like dynamic programming, greedy methods, and backtracking. Here is how I structured my approach over about ten weeks: First, I spent a few days just reading through the preliminaries chapter to check my baseline knowledge. Python's list comprehensions, generator expressions, and the collections module are essential here. If you are weak on those, the puzzles will feel much harder than they need to be.
Then I worked through puzzles in order, spending roughly forty-five minutes to an hour on each one before looking at the solution. The solutions section starts around page 180 and includes both reference implementations and explanations of the reasoning process. I found the reasoning explanations more valuable than the code itself. For the harder puzzles, especially the dynamic programming ones in the later chapters, I would sketch out small examples by hand before writing any code. This habit alone cut my solving time significantly. The book does not explicitly teach this strategy, but it emerges naturally from working through the material.
Get the Full Details

Counter-Intuitive Things I Learned
One insight that stuck with me was about recursion and state management. Beginners often think recursion is about writing the base case and the recursive call. The harder part is identifying and managing the state that needs to be preserved across calls. In the puzzle involving counting paths in a grid with obstacles, my recursive solution kept failing on larger inputs because I was recomputing subproblems repeatedly. Memoization fixed it, but the lesson was deeper: recursion without state tracking is just expensive enumeration. The book introduces this concept implicitly through the puzzles rather than teaching it as a standalone topic, which is actually more effective for retention. Another thing that surprised me was how much the linked list puzzles taught me about pointer manipulation in Python. Since Python handles memory automatically, people tend to overlook how linked list operations actually work at a structural level. The reverse-a-linked-list puzzle seems trivial until you try to do it iteratively without a dummy node and end up losing track of the tail. The book includes several puzzles that force you to handle edge cases like empty lists, single-node lists, and cycles. These edge cases matter in production code far more than most interview prep materials acknowledge.
Practical Limitations Of This Approach
The book is not perfect. The later chapters on advanced topics like network flow and string matching are lighter than the earlier material. Some puzzles have multiple valid approaches but the book presents only one solution, which limits your exposure to alternative strategies. I found myself occasionally googling alternative solutions for puzzles where I felt the provided approach was not the most generalizable. Another issue is that some puzzles assume a level of mathematical maturity that may frustrate readers who are coming purely from a coding background without strong discrete math foundations. The combinatorics puzzle in the counting chapter, for instance, requires comfort with permutations and combinations. If you are rusty on that, you will stall. For people who want more practice in the dynamic programming area, I would supplement this book with additional resources. The coverage here is good but not exhaustive. Problems involving multidimensional DP tables and state compression techniques are only lightly touched upon.
What Actually Works When You Sit Down To Solve
My workflow for each puzzle went like this. Read the problem statement once without writing anything. Restate it in my own words to make sure I understood it. Draw a small example with concrete numbers and trace through what the output should be by hand. Then I would try to identify what category the problem fell into. Arrays usually suggest two-pointer techniques or prefix sums. Trees suggest traversal patterns. Graphs suggest BFS or DFS variants. This categorization step is something the book does not explicitly teach but it becomes automatic after working through about twenty puzzles. After categorization, I would attempt a brute force solution first. Writing the brute force forces you to understand the problem deeply before optimizing. Then I would look for the optimization opportunity. This usually meant identifying overlapping subproblems, optimal substructure, or a monotonic property that could be exploited. The transition from brute force to optimized solution is where most of the learning happens, and it is a process the book guides you through implicitly. I kept a notebook where I recorded not just the solutions but the pattern I recognized and the mistake I made along the way. After completing roughly sixty puzzles, I started noticing recurring patterns that appeared across different problem types. The sliding window technique, for example, showed up in both array and string problems. The same principle applied regardless of the domain. This cross-pollination of techniques is the real value of working through a diverse set of puzzles rather than grinding hundreds of problems in a single category.

When To Move On
If you are stuck on a puzzle for more than two hours, the book recommends looking at the solution. I found this guideline reasonable. The goal is to learn the pattern, not to prove something to yourself. Understanding why a solution works is more valuable than spending hours on an approach that leads nowhere. That said, I would still attempt the problem again the next day without looking at the solution. The second attempt usually succeeds and reinforces the learning. The book works best when paired with actual coding practice. Reading about a solution and writing the solution are different activities. I would implement each solved puzzle in Python, test it against the book's examples, and then modify it to handle edge cases. This habit of extension and variation is what separates someone who has solved a hundred puzzles from someone who has merely read solutions to a hundred puzzles.