Avismara Hugoppalu
← All musings

Data Structures & Algorithms

I kept solving everything with dynamic programming

A confession, and the one question that fixed it — do the choices interact? The spine for a series on reaching for the lighter pattern instead of reflexively reaching for DP.

June 18, 2026 · 4 min read

TL;DR
I had a reflex: reach for dynamic programming on everything. The solutions were correct and overbuilt, and I had no intuition for the lighter pattern that was actually called for. The fix was a single question — do the choices interact? If past choices constrain future ones, you need DP. If the best move now can't hurt you later, you don't. This is the spine of a short series; each following post is a pattern I learned to reach for instead of reflexive DP.

A confession to open a series with: for a long stretch, my answer to almost every algorithm problem was dynamic programming. Subproblems, a cache, a recurrence — it works on a huge range of problems, so it became the hammer. The solutions passed. They were also frequently overbuilt: I'd carry a whole table of state through a problem whose right answer was a single greedy pass or two pointers walking inward. I could produce the heavy solution and had no feel for the light one.

That's not a knowledge gap. It's a recognition gap — not knowing which tool the problem is asking for. And it turned out one question resolves most of it.

Do the choices interact?

Every one of these patterns is a sequence of decisions. The thing that decides which pattern you need is whether those decisions are entangled.

The test. Make the best possible choice at this step. Can it ever hurt you later? Yes → the choices compound, past decisions constrain future ones, so you have to remember state: that's dynamic programming. No → the choices are independent, the locally best move is globally safe, and you can decide in one pass: that's greedy, two pointers, or a single sweep.

DP is what you reach for when you must remember where you've been. The moment you can prove you don't have to — that the greedy move now forecloses nothing — the table evaporates and a one-liner takes its place. Most of my overbuilt solutions were cases where the choices didn't actually interact and I'd assumed they did.

Don't hand me the rule — show me why it's safe

There's a second posture under this whole series, and it's the one that actually makes the patterns stick. When someone hands you "for this problem, move the shorter pointer" or "skip to the reset point," that's a recipe. Recipes don't transfer; the next problem looks different and the recipe doesn't fit. What transfers is the proof — the argument for why the cheap choice can't cost you later.

So every post here tries to bottom out in a mechanism, not a template:

  • greedy bottoms out in the exchange argument — a way to prove the local choice is safe.
  • sliding window bottoms out in a monotonicity prerequisite — the condition under which a window is even a legal tool.
  • monotonic stack bottoms out in amortized O(n) accounting — each element pushed once, popped once.
  • binary search on the answer bottoms out in a monotonic yes/no boundary — you're locating it, not building it.

The template, in each case, falls out of the reasoning by the end. It never opens the piece.

The series

Each post takes one pattern and derives it from the ground up — and, where it's honest, from the exact mistake I kept making while learning it.

The takeaway
DP isn't wrong; over-reaching for it is. The skill isn't knowing more patterns — it's asking, before you write anything, whether the choices in front of you actually interact. Most of the time the lighter tool is sitting right there, and the only thing in the way is the reflex.

Problems to practice

Problems to practice