19

I have been reading up on dynamic programming lately. Would like to hear from someone who started from scratch and now is pretty good at identifying and solving DP problems. I am struggling in identifying these problems as DP and framing a concise solution.

I have gone through most of the beginner DP problems and MIT resources etc

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
user110036
  • 305
  • 2
  • 6
  • Is it on a code contest site? Then there is 80% probability it is solved via DP. Is it something you're writing that's going into production (website, server, application, whatever)? Then there is 0% probability it is solved via DP. – davidbak Feb 24 '21 at 17:13

5 Answers5

19

I come from a physics background, and thus, lots of maths. I find easy to spot problems well suited to recursive/dynamic programming solutions by finding similarities with proof by induction.

In proof by induction you have two parts:

  • you prove that if something is true for iteration N, it is also true for iteration N+1
  • you prove that it is true for iteration 1

In recursive programming/dynamic programming:

  • you identify an exit condition (for example, you hard wire the solution for iteration 1)
  • you calculate solution for iteration N given the solution for iteration N-1

So, as others answered, it is a matter of experience and picking the hints, but you can re-use other skills to guide you. After that, you need to always have the two parts which I mentioned: if you don't, then it won't work.

For example, to generate all the permutations of a set:

  • exit condition: if you only have one element, return it
  • recursion: the permutations of a set of N items are the N sets of permutations you get by choosing each element and combining the with all the N-1 sets of (many) permutations of the subset you get by removing the element.
Sklivvz
  • 5,242
  • 19
  • 34
10

Most dynamic programming problems can be solved via memoization. Memoization is normally both more intuitive and easier to code. You may find it helpful to think in terms of memoization instead of DP.

It's usually easier to intuit whether a problem is well-suited towards memoization (the steps are the same as Slivvz's answer, but I think the mental shift is a little shorter). However, once you've solved a problem via memoization, you can examine how your memo cache is being filled and then fill it in order, without recursion...which changes your algorithm to a dynamic programming algorithm.

See also
Dynamic programming and memoization: bottom-up vs top-down approaches.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Brian
  • 4,480
  • 1
  • 22
  • 37
7

Dynamic programming is definitionally about two things:

  1. Optimal substructure
    Larger solutions can be derived from smaller solutions; solving is not bidirectional.

  2. Overlapping subproblems
    The small solutions will be reused many times. If the subproblems don’t overlap at all, then you don’t benefit from DP/memoisation; what you have is divide and conquer instead.

The general approach to DP problems is:

  • Write a naïve recursive or iterative version that works.

  • Notice that the function is doing redundant work.

  • Find a way to avoid doing that redundant work, often by memoisation.

Jon Purdy
  • 20,437
  • 7
  • 63
  • 95
  • All of these are true from a theoretical stand point. IMO a little more practice is needed to be more familiar at quick identification :) – user110036 Jan 04 '14 at 09:50
2

I'd never implemented a single dynamic programming solver - my background is applied maths/physics/numerical computing, not CS - until a few years ago when I started doing Project Euler problems. The DP-solvable problems there (e.g 76, 158, 161, 242, but there are many more) turned out to be pretty much my favourite kind. You do definitely get better at spotting when it'll be a useful technique: basically look for things which seem like they could be solved by some sort of recursive, divide-and-conquer approach where it's also possible to tame the explosion of pathways needing to be explored by recognising recurring subproblems and reusing the previously computed results; being able to identify the minimal state vector to memoise on - and what irrelevant "history" can be erased - is the crucial step.

timday
  • 2,502
  • 1
  • 18
  • 17
0

Here are how I do it:

  1. Choose a small sample size (eg 6th Fibonacci number).
  2. Write the solution on paper (draw a binary tree, tabulation, etc).
  3. Check if there are any similar nodes.

With practice, you will develop an intuition for recognizing DP problems.

hasn
  • 101