When you see these "smells" in a problem, reach for these patterns.
Trade space for time. Store values you've seen for instant lookup.
Use two indices moving toward each other (or same direction) to avoid nested loops.
Maintain a window [left, right] and expand/contract to satisfy constraints.
Halve the search space each step. Works on any monotonic function, not just arrays.
LIFO order naturally handles nesting. In Go, use a slice as a stack.
Think in pointer rewiring. Use dummy nodes, slow/fast pointers, and prev/curr/next.
Most tree problems are: what do I compute at this node given results from children?
DFS for reachability and exhaustive search. BFS for shortest path in unweighted graphs.
Define the state, write the recurrence, optimize space. Start with brute force recursion, add memoization.
A min-heap of size k keeps the k largest. A max-heap keeps the k smallest. In Go, negate values for max-heap.
Sort by start time, then scan left to right comparing current start with previous end.
Choose, explore, un-choose. Prune branches early when constraints are violated.
Shared prefixes share tree paths. O(m) lookup where m is the word length, regardless of dictionary size.