Dynamic Programming
Copyright © 直通硅谷
http://www.zhitongguigu.com/
What is Dynamic Programming?
A very powerful and general tool for solving certain optimization problems
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Dynamic Programming
VS Recursion
- Both are using sub-problems to solve the main problem
- Recursion is much more general
- If it can be solved by dynamic programming, DP is much faster
- Usually DP requires more space
- SPACE VS TIME
Copyright © 直通硅谷
http://www.zhitongguigu.com/
When we use DP?
- It can be resolved by recursion and not tail recursion
- Recursion is making some redundant computation
- It has to have optimal sub-structures:
optimal solutions to the original problem contains optimal solutions to sub-problems
Copyright © 直通硅谷
http://www.zhitongguigu.com/
When we use DP?
- It can be resolved by recursion and not tail recursion
- Recursion is making some redundant computation
Copyright © 直通硅谷
http://www.zhitongguigu.com/
It means:
1. If it cannot be solved by recursion, do not bother finding DP.
2. not all the recursion can use DP to solve. E.G. merge sort
What is Tail Recursion
- The recursion call happens at last
- It can always be rewritten into a loop
Copyright © 直通硅谷
http://www.zhitongguigu.com/
int A() {
...
...
A;
}
int Factorial(int n) {
if(n == 1) return 1;
return n * Factorial(n-1);
}
int Factorial(int n) {
int sum = 1;
for(int i = 1; i <= n; i ++) {
sum = sum * i;
}
return sum;
}
How to use DP?
- Think about the recursion solution
- Find sub problems that have been computed multiple times
- See if the sub problems are optimal sub-structure
- Try to memorize them to avoid the redundant computing
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Fibonacci Numbers
int Fabonacci(int n) {
if(n == 0 || n == 1) return 1;
return F(n-1) + F(n-2);
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Copyright © 直通硅谷
http://www.zhitongguigu.com/
F(6)
F(5)
F(4)
F(4)
F(3)
F(3)
F(3)
F(2)
F(2)
F(1)
F(1)
F(1)
F(0)
F(1)
F(0)
F(1)
F(0)
F(1)
F(0)
F(2)
F(1)
F(1)
F(0)
F(2)
F(2)
Need some space to avoid the computation
int Fabonacci(int n) {
if(n <= 1) return 1;
int[] result = new int[n + 1];
result[0] = 1;
result[1] = 1;
for(int i = 2; i < n + 1; i ++) {
result[i] = result[i-1] + result[i-2];
}
return result[n];
}
We use an Array to store the temp result
What is the optimal sub-structure?
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Unique Paths
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Unique Paths
Copyright © 直通硅谷
http://www.zhitongguigu.com/
int uniquePaths(int m, int n) {
if(m==1 || n==1) return 1;
return uniquePaths(m-1, n) + uniquePaths(m, n-1);
}
Where is the redundancy?
What is the optimal sub-structure?
Unique Paths
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Optimal Sub-structure
a(i,j) = a(i-1,j) + a(i, j-1)
Unique Paths
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int uniquePaths(int m, int n) {
int[][] a = new int[m][n];
for (int i = 0; i < m; i++) {
a[i][0] = 1;
}
for (int i = 0; i < n; i++) {
a[0][i] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
a[i][j] = a[i-1][j] + a[i][j-1];
}
}
return a[m-1][n-1];
}
Minimum Path Sum
Copyright © 直通硅谷
http://www.zhitongguigu.com/
1 | 3 | 4 | 2 |
---|---|---|---|
3 | 5 | 2 | 3 |
2 | 1 | 2 | 3 |
2 | 2 | 4 | 2 |
Best optimal sub-structure?
Minimum Path Sum
Copyright © 直通硅谷
http://www.zhitongguigu.com/
1 | 3 | 4 | 2 |
---|---|---|---|
3 | 5 | 2 | 3 |
2 | 1 | 2 | 3 |
2 | 2 | 4 | 2 |
PathSum(m,n) = MIN(PathSum(m,n-1),PathSum(m-1,n)) + matrix(m,n)
Minimum Path Sum
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int minPathSum(int[][] grid) {
if(grid == null || grid.length==0)
return 0;
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[m][n];
dp[0][0] = grid[0][0];
for(int i=1; i<n; i++){
dp[0][i] = dp[0][i-1] + grid[0][i];
}
for(int j=1; j<m; j++){
dp[j][0] = dp[j-1][0] + grid[j][0];
}
for(int i=1; i<m; i++){
for(int j=1; j<n; j++){
if(dp[i-1][j] > dp[i][j-1]){
dp[i][j] = dp[i][j-1] + grid[i][j];
}else{
dp[i][j] = dp[i-1][j] + grid[i][j];
}
}
}
return dp[m-1][n-1];
}
Minimum Path Sum
Copyright © 直通硅谷
http://www.zhitongguigu.com/
What is time complexity?
Can we do better?
What is space complexity?
Can we do better?
Any improvement?
Minimum Path Sum
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Any improvement?
We can use less space to get the same result without hurting time complexity
Minimum Path Sum II
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public static int minPathSum(int[][] grid) {
if(grid == null || grid.length==0)
return 0;
int m = grid.length;
int n = grid[0].length;
int[] newline = new int[n];
int[] oldline = new int[n];
oldline[0] = grid[0][0];
for(int i=1; i<n; i++){
oldline[i] = oldline[i-1] + grid[0][i];
}
for(int i=1; i<m; i++){
newline[0] = grid[i][0] + oldline[0];
for(int j=1; j<n; j++){
if(oldline[j] > newline[j-1]){
newline[j] = newline[j-1] + grid[i][j];
}else{
newline[j] = oldline[j] + grid[i][j];
}
}
oldline = newline;
}
return newline[n-1];
}
0-1 Knapsack
Given a knapsack which can hold w pounds of items, and a set of items with weight w1, w2, ... wn. Each item has its value s1,s2,...,sn. Try to select the items that could put in knapsack and contains most value.
What is the optimal sub-structure?
Copyright © 直通硅谷
http://www.zhitongguigu.com/
0-1 Knapsack
Copyright © 直通硅谷
http://www.zhitongguigu.com/
w[i][j]: for the previous total i items, the max value it can have for capacity j
Which two we need to use to compare?
w[i][j]: for the previous total i items, the max value it can have for capacity j
Copyright © 直通硅谷
http://www.zhitongguigu.com/
When you iterate i, and j, you need to try:
- If the new i could be added into j
- if it could and added, could it be better
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
2 | 0 | 3 | 3 | 8 | 11 | 11 | 11 | 11 |
3 | 0 | 3 | 3 | 8 | 11 | 11 | 11 | 12 |
4 | 0 | 3 | 3 | 8 | 11 | 11 | 11 | 12 |
w[i][j]: for the previous total i items, the max value it can have for capacity j
Example: weights{1,3,4,5} values{3,8,4,7}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int knapsack(int capacity, int[] weights, int[] values) {
int length = weights.length;
if (capacity == 0 || length == 0)
return 0;
int[][] w = new int[length + 1][capacity + 1];
for (int i = 1; i <= length; i++) {
int index = i - 1;
for (int j = 1; j <= capacity; j++) {
if (j < weights[index]) {
w[i][j] = w[i - 1][j];
} else if (w[i - 1][j - weights[index]] + values[index] > w[i - 1][j]) {
w[i][j] = w[i - 1][j - weights[index]] + values[index];
} else {
w[i][j] = w[i - 1][j];
}
}
}
return w[length][capacity];
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Longest Increasing Subsequence
3, 1, 4, 5, 7, 6, 8, 2
1, 4, 5, 6, 8 (Or 1, 4, 5, 7, 8)
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Longest Increasing Subsequence
What is the optimal sub-structure?
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Longest Increasing Subsequence
Copyright © 直通硅谷
http://www.zhitongguigu.com/
We store lis[i] for the LIS by i?
We store lis[i] for the LIS using sequence[i]
Longest Increasing Subsequence
public int longestIncreasingSubsequence(int[] nums) {
if(nums.length == 0){
return 0;
}
int[] lis = new int[nums.length];
int max = 0;
for (int i = 0; i < nums.length; i++){
int localMax = 0;
for (int j = 0; j < i; j++){
if (lis[j] > localMax && nums[j] <= nums[i]){
localMax = lis[j];
}
}
lis[i] = localMax + 1;
max = Math.max(max, lis[i]);
}
return max;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
What is the Time Complexity?
What is the Space Complexity?
Can we do better?
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Patient Sort
Copyright © 直通硅谷
http://www.zhitongguigu.com/
1, 3, 5, 2, 8, 4, 7, 6, 0, 9, 10
1 -> 0 |
1,3 -> 1,2 |
1,3,5 -> 1,3,4 |
1,3,5,8 -> 1,3,5,7 -> 1,3,5,6 |
1,3,5,6,9 |
1,3,5,6,9,10 |
public int longestIncreasingSubsequence(int[] nums) {
if(nums.length == 0){
return 0;
}
int len = 0;
int[] tails = new int[nums.length];
tails[0] = nums[0];
for(int i = 1; i < nums.length; i++){
if(nums[i] < tails[0]){
tails[0] = nums[i];
} else if (nums[i] >= tails[len]){
tails[++len] = nums[i];
} else {
tails[binarySearch(tails, 0, len, nums[i])] = nums[i];
}
}
return len + 1;
}
private int binarySearch(int[] tails, int min, int max, int target){
while(min < max){
int mid = min + (max - min) / 2;
if(tails[mid] == target){
return mid;
}
else if(tails[mid] < target){
min = mid + 1;
}
else max = mid;
}
return min;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Longest Common Sequence
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Longest Common Sequence
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Example: abcfbc abfcab
return 4 (abcb)
Longest Common Sequence
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Example: abcfbc abfcab
return 4 (abcb)
Longest Common Sequence
What is the optimal sub-structure?
maxCommon(i,j): longest common string for String A(0,i) and String B(0,j)
We finally need to get maxCommon(stringA.length, stringB.length)
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Longest Common Sequence
Copyright © 直通硅谷
http://www.zhitongguigu.com/
What is the relationship between maxCommon(i,j) and maxCommon(i-1,j-1)?
If(A[i-1] = B[j-1]) ?
If(A[i-1] != B[j-1])?
Longest Common Sequence
Copyright © 直通硅谷
http://www.zhitongguigu.com/
What is the relationship between maxCommon(i,j) and maxCommon(i-1,j-1)?
If(A[i-1] = B[j-1]) ?
If(A[i-1] != B[j-1])?
maxCommon(i,j) = maxCommon(i-1,j-1) + 1
maxCommon(i,j) = max(maxCommon(i-1,j), maxCommon(i,j-1))
Longest Common Sequence
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public static int longestCommonString(String a, String b) {
int m = a.length();
int n = b.length();
int[][] maxCommon = new int[m+1][n+1];
for(int i = 0; i <= m; i ++) {
maxCommon[i][0] = 0;
}
for(int j = 0; j <= n; j ++) {
maxCommon[0][j] = 0;
}
for(int i = 1; i <= m; i ++) {
for(int j = 1; j <= n; j ++) {
if(a.charAt(i-1) == b.charAt(j-1)) {
maxCommon[i][j] = maxCommon[i-1][j-1] + 1;
}
else {
maxCommon[i][j] = Math.max(maxCommon[i][j-1], maxCommon[i-1][j]);
}
}
}
return maxCommon[m][n];
}
Matrix Multiplication
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Matrix A m*n
Matrix B n*p
C = A * B will need m*n*p times multiplication
A 100 * 10, B 10 * 100, C 100 * 5
D = A * B * C
If we do (AB)C, need 100*10*100 + 100*100*5 = 150000 times
If we do A(BC), need 100*10*5 + 10*100*5 = 10000 times
Matrix Multiplication
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Give A0,A1,.....,An-1 n different matrixs
Find minimum of multiplication it needs to get the result
input: An array P with n+1 numbers
A0 = p0*p1, An-1 = Pn-1*Pn
Matrix Multiplication
Copyright © 直通硅谷
http://www.zhitongguigu.com/
What is the optimal sub-structure?
For the result A1*...*An, if we split from Ak
It becomes (A1*...Ak)(Ak+1*...An)
T(1,n) = T(1,k) + T(k+1,n) + p0*pk*pn
So if T(1,n) is the best, T(1,k) and T(k+1,n) must be the best
Matrix Multiplication
Copyright © 直通硅谷
http://www.zhitongguigu.com/
So how do we get the T(1,k)?
We need to start from the chain with length 1 to finally get to length n
public static int MatrixChain(int[] p)
{
int n = p.length;
n --;
int[][] m = new int[n][n];
for(int i = 0; i < n; i++)
m[i][i] = 0;
for(int r = 2; r <= n; r++)
{
for(int i = 0; i < n - r + 1; i ++)
{
int j = i + r - 1;
m[i][j] = m[i + 1][j] + p[i] * p[i+1] * p[j + 1];
for(int k = i + 1; k < j; k++)
{
int t = m[i][k] + m[k + 1][j] + p[i] * p[k+1] * p[j+1];
if( t < m[i][j])
m[i][j] = t;
}
}
}
return m[0][n-1];
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Edit Distance
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Replace: abc -> abd
Remove: abc -> ab
Add: abc -> abcd
How many steps you need from String A to B?
e.g. abca -> eeba 3 steps
abcdf -> eecf 3 steps
Edit Distance
Copyright © 直通硅谷
http://www.zhitongguigu.com/
What is the optimal sub-structure?
what is the connection between EDIT[i,j]
and EDIT[i-1,j], EDIT[i,j-1] and EDIT[i-1,j-1]?
Edit Distance
Copyright © 直通硅谷
http://www.zhitongguigu.com/
what is the connection between EDIT[i,j]
and EDIT[i-1,j], EDIT[i,j-1] and EDIT[i-1,j-1]?
if(A[i-1]!=B[j-1])?
if(A[i-1]=B[j-1])?
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public static int editDistance(String a, String b) {
int m = a.length() + 1;
int n = b.length() + 1;
int[][] f = new int[m][n];
for(int i = 0; i < m; i ++) {
f[i][0] = i;
}
for(int j = 0; j < n; j ++) {
f[0][j] = j;
}
for(int i = 1; i < m; i ++) {
for(int j = 1; j < n; j ++) {
if(a.charAt(i-1) == b.charAt(j-1)) {
f[i][j] = f[i-1][j-1];
}
else {
f[i][j] = f[i-1][j-1] + 1;
}
f[i][j] = Math.min(f[i][j], Math.min(f[i-1][j]+1, f[i][j-1]+1));
}
}
return f[m-1][n-1];
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Homework
Unique Path II
Climbing Stairs
Maximum Subarray
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Homework (Optional)
Longest Valid Parentheses
Triangle
Best Time to Buy and Sell Stock
Distinct Subsequences
[GoValley-201612] Dynamic Programming
By govalley201612
[GoValley-201612] Dynamic Programming
- 698