Best Practices & Common Patterns Recap
This is the last stop in the DSA in Python track. Rather than introducing anything new, this page recaps the handful of habits and pattern signals that mattered across all 30 lessons before it — the things worth carrying with you into an actual interview, long after the specific code examples have faded from memory — plus a dedicated rundown of the Python-specific traps this track called out along the way.
The Recap Checklist
- Recognize patterns, don't memorize solutions. A new problem is rarely "new" — it's almost always a familiar pattern (two pointers, sliding window, DP, etc.) wearing a different word problem. Memorizing 500 individual solutions is brittle; recognizing 8-10 patterns is durable.
- Always state complexity, unprompted. Don't wait to be asked "what's the time complexity?" — say it as a natural part of explaining your own solution. It signals that complexity is part of how you think, not a fact you look up afterward.
- Practice writing code without an IDE occasionally. Whiteboard or plain paper, no autocomplete, no red squiggly underlines. This forces you to actually know method names and syntax rather than leaning on tooling that won't be there in a live interview (or that some interviews deliberately restrict).
- See structures combined, not in isolation. Real problems often stack a pattern on top of a structure — a graph problem that also needs a queue (BFS) or a heap (Dijkstra), or a DP problem that also needs a dict for memoization.
- Trace your own code by hand before declaring it done. A 30-second trace on a small example catches the off-by-one errors that a silent "looks right" review misses.
Pattern → When To Use It
| Pattern | Signal that it applies |
|---|---|
| Two pointers | A sorted list (or one you can sort) where you're looking for a pair, triple, or need to compare elements from both ends inward. |
| Sliding window | A contiguous subarray/substring problem with a running condition — max/min sum, longest substring without repeats, smallest window containing X. |
| Dynamic programming | "Count the ways," "minimum/maximum cost," or "is it possible" phrased over a problem with overlapping subproblems and optimal substructure — the same smaller decision recurs inside bigger ones. |
| Backtracking | "Find all combinations/arrangements/subsets" under constraints — you need to explore every possibility but can prune branches that already violate a rule. |
| BFS / DFS | Anything phrased in terms of nodes, edges, or connections — reachability, shortest path in an unweighted graph (BFS), or exploring all paths/components (DFS). |
| Greedy | "Make the locally best choice at each step" problems where you can prove (or have seen proven) that local optimality leads to global optimality — interval scheduling, coin change with canonical denominations, MST construction. |
Python Interview Gotchas Recap
- list.pop(0) vs. deque: popping (or inserting) at the front of a Python list is O(n) — every remaining element shifts. If a problem needs fast operations at both ends, reach for collections.deque instead, which is O(1) on both ends. This is exactly why the Queue lesson used deque and not a plain list.
- heapq is min-only: Python's heap module only gives you a min-heap directly. For a max-heap, negate the values going in and out (push -x, read back -heapq.heappop(...)), or store (-priority, item) tuples.
- Mutable default arguments are a classic footgun: writing def f(items=[]): creates that empty list once, when the function is defined — not fresh on every call. Every call that relies on the default shares and mutates the same list, so state silently leaks between unrelated calls. The fix, used throughout this track's memoization code: default to None and create the real mutable object inside the function body — def f(items=None): items = items if items is not None else [].
- The recursion limit: Python's default recursion depth ceiling is around 1000 frames (sys.getrecursionlimit()), far lower than what a deep unbalanced tree or a large-n naive recursive solution might need — hitting it raises RecursionError. Bottom-up (iterative) DP sidesteps this entirely, which is one more reason to keep it in your toolkit even when top-down feels more natural to derive.
One Last Reminder on Complexity
Every single code example across all 31 lessons in this track ended with an explicit time and space complexity line, and that wasn't incidental formatting — it's the habit this whole track was built to install. If you take one thing forward, let it be this: complexity isn't a fact you compute after the fact for a grade, it's a lens for evaluating your own solution as you build it.