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:

  1. If the new i could be added into j
  2. 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

Made with Slides.com