#DP

1. Dynamic Programming

A method for solving a complex problem by breaking it down into a collection of simpler sub-problems.

1.1 When to use

  1. One of the following three:
  • Maximum/Minimum Problem
  • Yes or No Question
  • Count all possible solutions
  1. Can’t do sort or swap operation

Note: DP can’t return all results, it only returns max/min, yes/no or a certain value(like length, possible solutions, etc.).

1.2 How to think

  1. States: what we need to store for each sub-problem (usually an array).
  2. Function: what is the relationship between each state.
  3. Intialization: what is the start of each state.
  4. Answer: what is the end of each state.

Example: Number Triangle
We use an array f[i][j] to record the minimum sum from (0, 0) to (i, j). For a certain (i, j), we know it is either from (i - 1, j - 1) or (i - 1, j). So the sub-problem is to traverse all elements in the triangle and calculate all the f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + T[i]][j]. The result will be the minimum one in f[n - 1][0, ..., n - 1].
We can also do it from bottom up. First we find the minimum of each pair in the last row, then we do above similarly but from bottom up. Finally the only one element left in the array is the result we are looking for.
A bonus point is doing this using only O(n) extra space, where n is the total number of rows in the triangle. Since each time we calculate f[i][j], the result is only related with f[i - 1][], we can only use 1D array and update the elements in it in each for loop.
Here is the code from bottom up with O(n) space cost.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
if(triangle.size() == 0) {
return 0;
}

int[] result = new int[triangle.size() + 1];

for(int row = triangle.size() - 1; row >= 0; row--) {
for(int col = 0; col <= row; col++) {
result[col] = Math.min(result[col], result[col + 1]) + triangle.get(row).get(col);
}
}

return result[0];
}
}

Dynamic Programming uses extra space to remember the mid-result. So that it is more efficient than recursive searching, which may repeated calculate the same mid-result for many times. In the above example, if we do a brute force search, it cost O(2^n) time, where n is the height of the triangle (each row, we need to choose one from two, totally n rows). But it only costs O(n^2) in theoretical(m rows, each row has n elements, totally n^2) or O(n), which means all numbers we only need to visit once.

Read More

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×