0.Basic Concepts
Dynamic Programming (DP): is a method for solving a complex problem by breaking it down into a collection of simpler subproblems, solving each of those subproblems just once, and storing their solutions - ideally, using a memory-based data structure.1.The difference between DP and divide-and-conquer
Divide-and-conquer partitions the problem into disjoint subproblems while DP partitions the problem into overlapped subproblems.2.Typical DP problems
- A problem can have many solutions, each solution has a value, try to find the solution with optimal value.
- Try to find the total number of solutions of a problem.
3.Solution
- Define the structure of an optimal solution.
- Recursively define the value of an optimal solution.
- Compute the value of an optimal solution in a bottom-up fashion.
If we only need the value of the optimal solution, the above 3 steps are enough. - Construct an optimal solution from computed information. (Usually, step 4 requires us to maintain some additional information to construct the optimal solution.)
4.Typical Examples (examples are all from Leetcode.com)
I strongly recommend you to read the following two articles:
[Type 1] find the solution with optimal value
- [Type 1-1] Index-based based bottom-up method:
[A typical question 1-1] Given an array arr[], find the continuous subarray which has the maximum sum, output the sum value.
e.g., [1, -2, 3, 4, -2] -> 7 (becuase 3+4=7)
[How to define dp[i]]
The "optimal subsolution dp[i]" can be constructed in 2 ways:
1.dp[i] is the optimal solution for the subarray arr[0:i]
e.g., in the example, dp = [1,1,3,7,7]
The output should be dp[arr.length-1], which is 7.
2.dp[i] is the optimal solution whose last element is arr[i] for the subarray arr[0:i]
e.g., in the example, dp = [1,-1,3,7,5]
The output should be maximum value in dp[], which is 7.
(A brief explanation: dp[1]=-1 is because dp[1] must contain the lase element arr[1], so the subarray can be [1,-2] or [-2], apparently the first subarray's sum is larger. So dp[1] = 1+(-2) = 1.
[Bottom up process] The bottom up process is from i=0 to i=arr.length-1. This is different from value-based problem. We will talk about this later.
[Practice] - array:
- [53] Maximum Subarray
- [152] Maximum Product of Subarray
- [32] Longest Valid Parentheses
- [300] Longest Increasing Subsequence
- [368] Largest Divisible Subset
- [139] Word Break
- matrix:
- [120] Triangle
- [64] Minimum Path Sum
- [221] Maximal Square
- [174] Dungeon Game (Note, from bottom right to top left)
- [354] Russian Doll Envelopes
- [363] Max Sum of Rectangle No Larger Than K
- [32] Longest Valid Parentheses
- [Type 1-2] Index-based bottom-up method, with multiple states.
[Question 1-2] adds some extra constraints on type 1-1. The constraint might lead to multiple states. Sometimes, solution 1-1 could solve such situation. However, sometimes it does not work.
[Solution 1-2] use extra arrays each corresponding to one condition. (Or add one dimension, e.g., array arr[] ->matrix arr[][], dp[i][0] corresponds to state 0, dp[i][1] corresponds to state 1, etc).
[Practice]
- [198] House Robber
([soln], two states: rob the first house/not, the bottom-up method needs to maintain 2 arrays, one corresponding to "rob the 1st house", another corresponding to "not rob the 1st house". Similarly, we can also maintain a matrix arr[][], arr[i][0] corresponds to "not rob the first house" while arr[i][1] corresponds to "rob the first house".) - [213] House Robber II
- [256] Paint House (3 states/colors)
- [265] Paint House II (k states/colors)
- [276] Paint Fence
- [123] Best Time to Buy and Sell Stock III
- [188] Best Time to Buy and Sell Stock IV
- [309] Best Time to Buy and Sell Stock with Cooldown
dp[start][end] variation: The substructure (subarray) is arr[start:end] rather than arr[0:end]. We can understand in this way: A subarray ending at j can starts from i = 0 to j-1. Each i corresponds to a state. So we should construct dp as dp[i][j], which represents the optimal solution for subarray[i:j].
- [Type 1-3] Value-based bottom-up method
[A typical question 1-3] "Given a number n and an array arr[], try to find the minimum set of numbers from arr whose sum is equal to n".
[How to define dp[i]] dp[i] corresponds to the optimal set whose sum is equal to i.
[Bottom up process] The bottom up process is from i=0 to i=n. This is the biggest difference between index-based problem and value-based problem. In the index-based problem, the bottom up process is from i=0 to i=arr.length-1.
[Practice]
No comments:
Post a Comment