Dynamic Programming

Factorial using DP

Memoization

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int[] memo;

    static int fib(int n) {
        if (memo[n] == -1) {
            int res;

            if (n == 0 || n == 1)
                return n;

            else {
                res = fib(n - 1) + fib(n - 2);

            }

            memo[n] = res;

        }

        return memo[n];
    }

    public static void main(String[] args) {

        int n = 5;

        memo = new int[n + 1];

        Arrays.fill(memo, -1);

        out.println(fib(n));

    }
}

Tabulation

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int fib(int n) {
        int f[] = new int[n + 1];

        f[0] = 0;
        f[1] = 1;

        for (int i = 2; i <= n; i++) {
            f[i] = f[i - 1] + f[i - 2];
        }

        return f[n];

    }

    public static void main(String[] args) {

        int n = 5;

        out.println(fib(n));

    }
}

Longest Common Subsequence (Part 1)

Memoization

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int[][] memo;

    static int lcs(String s1, String s2, int n, int m) {
        if (memo[n][m] != -1)
            return memo[n][m];

        if (n == 0 || m == 0)
            memo[n][m] = 0;

        else {
            if (s1.charAt(n - 1) == s2.charAt(m - 1))
                memo[n][m] = 1 + lcs(s1, s2, n - 1, m - 1);
            else
                memo[n][m] = Math.max(lcs(s1, s2, n - 1, m), lcs(s1, s2, n, m - 1));
        }

        return memo[n][m];

    }

    public static void main(String[] args) {

        String s1 = "AXYZ", s2 = "BAZ";

        int n = 4, m = 3;

        memo = new int[n + 1][m + 1];

        for (int[] i : memo) {
            Arrays.fill(i, -1);
        }

        System.out.println(lcs(s1, s2, n, m));

    }
}

Tabulation

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int lcs(String s1, String s2) {
        int m = s1.length(), n = s2.length();

        int dp[][] = new int[m + 1][n + 1];

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (s1.charAt(i - 1) == s2.charAt(j - 1))
                    dp[i][j] = 1 + dp[i - 1][j - 1];
                else
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }

        return dp[m][n];

    }

    public static void main(String[] args) {

        String s1 = "AXYZ", s2 = "BAZ";

        System.out.println(lcs(s1, s2));

    }
}

Variation of LCS

  • Diff Utility

  • Min. insert or delete to convert s1 to s2

  • Short common sequence

  • Longest Palindrome Sub sequence

  • Longest Repeating Sub sequence

  • Printing LCS

Coin Change Count Combinations

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int getCount(int coins[], int n, int sum) {
        int dp[][] = new int[sum + 1][n + 1];

        for (int i = 0; i <= n; i++) {
            dp[0][i] = 1;
        }

        for (int i = 1; i <= sum; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = dp[i][j - 1];

                if (coins[j - 1] <= i)
                    dp[i][j] += dp[i - coins[j - 1]][j];
            }
        }

        return dp[sum][n];

    }

    public static void main(String[] args) {

        int coins[] = { 1, 2, 3 }, sum = 4, n = 3;

        System.out.println(getCount(coins, n, sum));

    }
}

Edit Distance Problem

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int eD(String s1, String s2, int m, int n) {
        if (m == 0)
            return n;
        if (n == 0)
            return m;

        if (s1.charAt(m - 1) == s2.charAt(n - 1))
            return eD(s1, s2, m - 1, n - 1);
        else {
            return 1 + Math.min(eD(s1, s2, m, n - 1), Math.min(eD(s1, s2, m - 1, n), eD(s1, s2, m - 1, n - 1)));
        }

    }

    public static void main(String[] args) {

        String s1 = "CAT", s2 = "CUT";
        int n = 3, m = 3;

        System.out.println(eD(s1, s2, m, n));

    }
}

Edit Distance Problem DP

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int eD(String s1, String s2, int m, int n) {
        int dp[][] = new int[m + 1][n + 1];

        for (int i = 0; i <= m; i++) {
            dp[i][0] = i;
        }

        for (int j = 0; j <= n; j++) {
            dp[0][j] = j;
        }

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1]));

                }
            }
        }

        return dp[m][n];
    }

    public static void main(String[] args) {

        String s1 = "CAT", s2 = "CUT";
        int n = 3, m = 3;

        System.out.println(eD(s1, s2, m, n));

    }
}

Longest Increasing Subsequence Problem

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int LIS(int arr[], int n) {
        int lis[] = new int[n];

        lis[0] = 1;

        for (int i = 1; i < n; i++) {
            lis[i] = 1;
            for (int j = 0; j < i; j++)
                if (arr[i] > arr[j])
                    lis[i] = Math.max(lis[i], lis[j] + 1);
        }

        int res = lis[0];

        for (int i = 0; i < n; i++) {
            res = Math.max(lis[i], res);
        }

        return res;

    }

    public static void main(String[] args) {
        int arr[] = { 3, 4, 2, 8, 10, 5, 1 };
        int n = 7;

        System.out.println(LIS(arr, n));

    }
}

Longest Increasing Subsequence O( nlog(n) )

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int ceilIdx(int tail[], int l, int r, int key) {
        while (r > l) {
            int m = l + (r - l) / 2;
            if (tail[m] >= key)
                r = m;
            else
                l = m + 1;
        }

        return r;
    }

    static int LIS(int arr[], int n) {

        int[] tail = new int[n];
        int len = 1;

        tail[0] = arr[0];

        for (int i = 1; i < n; i++) {

            if (arr[i] > tail[len - 1]) {
                tail[len] = arr[i];
                len++;
            } else {
                int c = ceilIdx(tail, 0, len - 1, arr[i]);

                tail[c] = arr[i];
            }
        }

        return len;
    }

    public static void main(String[] args) {
        int arr[] = { 3, 10, 20, 4, 6, 7 };
        int n = 6;

        System.out.println(LIS(arr, n));

    }
}

Variation of LIS

  • Minimum deletions to make array sorted

  • Maximum Sum Increasing Sub sequence

  • Max Length Bitonic Solution

  • Building Bridges

  • The longest chain

Maximum Cuts

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int maxCuts(int n, int a, int b, int c) {

        int dp[] = new int[n + 1];

        dp[0] = 0;

        for (int i = 1; i <= n; i++) {
            dp[i] = -1;

            if (i - a >= 0)
                dp[i] = Math.max(dp[i], dp[i - a]);

            if (i - b >= 0)
                dp[i] = Math.max(dp[i], dp[i - b]);

            if (i - c >= 0)
                dp[i] = Math.max(dp[i], dp[i - c]);

            if (dp[i] != -1)
                dp[i]++;
        }

        return dp[n];

    }

    public static void main(String[] args) {
        int n = 5, a = 1, b = 2, c = 3;

        System.out.println(maxCuts(n, a, b, c));

    }
}

Minimum coins to make a value

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int minCoins(int arr[], int m, int value) {

        int dp[] = new int[value + 1];

        dp[0] = 0;

        for (int i = 1; i <= value; i++)
            dp[i] = Integer.MAX_VALUE;

        for (int i = 1; i <= value; i++) {

            for (int j = 0; j < m; j++)
                if (arr[j] <= i) {
                    int sub_res = dp[i - arr[j]];
                    if (sub_res != Integer.MAX_VALUE && sub_res + 1 < dp[i])
                        dp[i] = sub_res + 1;

                }

        }
        return dp[value];

    }

    public static void main(String[] args) {
        int arr[] = { 3, 4, 1 }, val = 5, n = 3;

        System.out.println(minCoins(arr, n, val));

    }
}

Minimum Jumps to reach at end

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int minJumps(int arr[], int n) {

        int dp[] = new int[n];
        int i, j;

        dp[0] = 0;

        for (i = 1; i < n; i++) {
            dp[i] = Integer.MAX_VALUE;
            for (j = 0; j < i; j++) {
                if (i <= j + arr[j] && dp[j] != Integer.MAX_VALUE) {
                    dp[i] = Math.min(dp[i], dp[j] + 1);
                    break;
                }
            }
        }
        return dp[n - 1];
    }

    public static void main(String[] args) {
        int arr[] = { 3, 4, 2, 1, 2, 1 }, n = 6;

        System.out.println(minJumps(arr, n));

    }
}

0-1 knapsack problem

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int knapSack(int W, int wt[], int val[], int n) {

        if (n == 0 || W == 0)
            return 0;

        if (wt[n - 1] > W)
            return knapSack(W, wt, val, n - 1);

        else
            return Math.max(val[n - 1] + knapSack(W - wt[n - 1], wt, val, n - 1), knapSack(W, wt, val, n - 1));
    }

    public static void main(String[] args) {
        int val[] = { 10, 40, 30, 50 };
        int wt[] = { 5, 4, 6, 3 };
        int W = 10;
        int n = 4;

        System.out.println(knapSack(W, wt, val, n));

    }
}

0-1 knapsack problem DP Solution

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int knapSack(int W, int wt[], int val[], int n) {

        int dp[][] = new int[n + 1][W + 1];

        for (int i = 0; i <= W; i++) {
            dp[0][i] = 0;
        }

        for (int i = 0; i <= n; i++) {
            dp[i][0] = 0;
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= W; j++) {
                if (wt[i - 1] > j)
                    dp[i][j] = dp[i - 1][j];
                else
                    dp[i][j] = Math.max(val[i - 1] + dp[i - 1][j - wt[i - 1]], dp[i - 1][j]);
            }
        }

        return dp[n][W];
    }

    public static void main(String[] args) {
        int val[] = { 10, 40, 30, 50 };
        int wt[] = { 5, 4, 6, 3 };
        int W = 10;
        int n = 4;

        System.out.println(knapSack(W, wt, val, n));

    }
}

Optimal Strategy for a Game

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int sol(int[] arr, int n) {
        int dp[][] = new int[n][n];

        for (int i = 0; i < n - 1; i++) {
            dp[i][i + 1] = Math.max(arr[i], arr[i + 1]);
        }

        for (int gap = 3; gap < n; gap = gap + 2) {
            for (int i = 0; i + gap < n; i++) {
                int j = gap + i;

                dp[i][j] = Math.max((arr[i] + Math.min(dp[i + 1][j], dp[i + 1][j - 1])),
                        (arr[i] + Math.min(dp[i + 1][j - 1], dp[i][j - 2])));
            }
        }

        return dp[0][n - 1];
    }

    public static void main(String[] args) {

        int n = 4;

        int arr[] = { 20, 5, 4, 6 };

        System.out.println(sol(arr, n));

    }
}

Egg Dropping Puzzle - Part 1

public class GFG {

    /*
     * Function to get minimum number of trials needed in worst case with n eggs and
     * k floors
     */
    static int eggDrop(int n, int k) {
        // If there are no floors, then
        // no trials needed. OR if there
        // is one floor, one trial needed.
        if (k == 1 || k == 0)
            return k;

        // We need k trials for one egg
        // and k floors
        if (n == 1)
            return k;

        int min = Integer.MAX_VALUE;
        int x, res;

        // Consider all droppings from
        // 1st floor to kth floor and
        // return the minimum of these
        // values plus 1.
        for (x = 1; x <= k; x++) {
            res = Math.max(eggDrop(n - 1, x - 1), eggDrop(n, k - x));
            if (res < min)
                min = res;
        }

        return min + 1;
    }

    // Driver code
    public static void main(String args[]) {
        int n = 2, k = 10;
        System.out.print("Minimum number of " + "trials in worst case with " + n + " eggs and " + k + " floors is "
                + eggDrop(n, k));
    }

}

Egg Dropping Puzzle - Part 2

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int res(int e, int f) {

        int dp[][] = new int[f + 1][e + 1];

        for (int i = 1; i <= e; i++) {
            dp[1][i] = 1;
            dp[0][i] = 0;
        }

        for (int j = 1; j <= f; j++) {
            dp[j][1] = j;
        }

        for (int i = 2; i <= f; i++) {
            for (int j = 2; j <= e; j++) {
                dp[i][j] = Integer.MAX_VALUE;
                for (int x = 1; x <= i; x++) {
                    dp[i][j] = Math.min(dp[i][j], 1 + Math.max(dp[x - 1][j - 1], dp[i - x][j]));
                }
            }
        }

        return dp[f][e];
    }

    public static void main(String[] args) {

        int n = 2;

        int f = 10;

        System.out.println(res(n, f));

    }
}

Count BSTs with n keys

A recursive structure is discussed, then a dynamic programming solution is discussed, finally relation with Catalan Numbers.

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int countBSTs(int n) {
        int dp[] = new int[n + 1];

        dp[0] = 1;

        for (int i = 1; i <= n; i++) {
            dp[i] = 0;

            for (int j = 0; j < i; j++) {
                dp[i] += dp[j] * dp[i - j - 1];
            }
        }

        return dp[n];
    }

    public static void main(String[] args) {

        int n = 4;

        System.out.println(countBSTs(n));

    }
}

Maximum sum with no two consecutive

DP-Code in O(1) space

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int maxSum(int arr[], int n) {
        if (n == 0)
            return arr[0];

        int prev_prev = arr[0];
        int prev = Math.max(arr[0], arr[1]);
        int res = prev;

        for (int i = 3; i <= n; i++) {
            res = Math.max(prev, prev_prev + arr[i - 1]);

            prev_prev = prev;

            prev = res;
        }

        return res;
    }

    public static void main(String[] args) {

        int n = 5, arr[] = { 10, 20, 30, 40, 50 };

        System.out.println(maxSum(arr, n));

    }
}

DP-Code in O(n) space

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int maxSum(int arr[], int n) {
        if (n == 0)
            return arr[0];

        int dp[] = new int[n + 1];

        dp[1] = arr[0];
        dp[2] = Math.max(arr[0], arr[1]);

        for (int i = 3; i <= n; i++) {
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + arr[i - 1]);
        }

        return dp[n];
    }

    public static void main(String[] args) {

        int n = 5, arr[] = { 10, 20, 30, 40, 50 };

        System.out.println(maxSum(arr, n));

    }
}

Subset Sum Problem (Recursive Solution)

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int countSubsets(int arr[], int n, int sum) {
        if (n == 0)
            return sum == 0 ? 1 : 0;

        return countSubsets(arr, n - 1, sum) + countSubsets(arr, n - 1, sum - arr[n - 1]);
    }

    public static void main(String[] args) {

        int n = 3, arr[] = { 10, 20, 15 }, sum = 25;

        System.out.println(countSubsets(arr, n, sum));

    }
}

Subset Sum Problem (DP Solution)

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static int countSubsets(int arr[], int n, int sum) {
        int dp[][] = new int[n + 1][sum + 1];

        for (int i = 0; i <= n; i++)
            dp[i][0] = 1;
        for (int j = 1; j <= sum; j++)
            dp[0][j] = 0;

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= sum; j++) {
                if (j < arr[i - 1])
                    dp[i][j] = dp[i - 1][j];
                else
                    dp[i][j] = dp[i - 1][j] + dp[i][j - arr[i - 1]];
            }
        }

        return dp[n][sum];
    }

    public static void main(String[] args) {

        int n = 3, arr[] = { 2, 5, 3 }, sum = 5;

        System.out.println(countSubsets(arr, n, sum));

    }
}

Matrix Chain Multiplication

/* A naive recursive implementation that simply follows 
the above optimal substructure property */
class MatrixChainMultiplication {
    // Matrix Ai has dimension p[i-1] x p[i] for i = 1..n
    static int MatrixChainOrder(int p[], int i, int j) {
        if (i + 1 == j)
            return 0;

        int min = Integer.MAX_VALUE;

        // place parenthesis at different places between first
        // and last matrix, recursively calculate count of
        // multiplications for each parenthesis placement and
        // return the minimum count
        for (int k = i + 1; k < j; k++) {
            int count = MatrixChainOrder(p, i, k) + MatrixChainOrder(p, k, j) + p[i] * p[k] * p[j];

            if (count < min)
                min = count;
        }

        // Return minimum count
        return min;
    }

    // Driver program to test above function
    public static void main(String args[]) {
        int arr[] = new int[] { 40, 20, 30, 10, 30 };
        int n = arr.length;
        System.out.println("Minimum number of multiplications is " + MatrixChainOrder(arr, 0, n - 1));

    }
}

Matrix Chain Multiplication (DP Solution)

/* A naive recursive implementation that simply follows 
the above optimal substructure property */
class MatrixChainMultiplication {
    // Matrix Ai has dimension p[i-1] x p[i] for i = 1..n
    static int MatrixChainOrder(int p[]) {
        int n = p.length;
        int dp[][] = new int[n][n];
        for (int i = 0; i < n - 1; i++)
            dp[i][i + 1] = 0;

        for (int gap = 2; gap < n; gap++) {
            for (int i = 0; i + gap < n; i++) {
                int j = i + gap;
                dp[i][j] = Integer.MAX_VALUE;
                for (int k = i + 1; k < j; k++) {
                    dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k][j] + p[i] * p[k] * p[j]);
                }
            }
        }

        return dp[0][n - 1];
    }

    // Driver program to test above function
    public static void main(String args[]) {
        int arr[] = new int[] { 40, 20, 30, 10, 30 };
        int n = arr.length;
        System.out.println("Minimum number of multiplications is " + MatrixChainOrder(arr));

    }
}

Palindrome Partitioning

/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
import static java.lang.System.out;

class GFG {

    static boolean isPalindrome(String input, int start, int end) {
        // Using two pointer technique to check pallindrome
        while (start < end) {
            if (input.charAt(start) != input.charAt(end))
                return false;
            start++;
            end--;
        }
        return true;
    }

    static int palPart(String str) {
        int n = str.length();

        int dp[][] = new int[n][n];

        for (int i = 0; i < n; i++) {
            dp[i][i] = 0;
        }

        for (int gap = 1; gap < n; gap++) {
            for (int i = 0; i + gap < n; i++) {
                int j = i + gap;

                if (isPalindrome(str, i, j)) {
                    dp[i][j] = 0;
                } else {
                    dp[i][j] = Integer.MAX_VALUE;

                    for (int k = i; k < j; k++) {
                        dp[i][j] = Math.min(dp[i][j], 1 + dp[i][k] + dp[k + 1][j]);
                    }
                }
            }
        }

        return dp[0][n - 1];
    }

    public static void main(String[] args) {

        String s = "geek";

        System.out.println(palPart(s));

    }
}

Allocate Minimum Pages (Naive Method)

import java.util.*;
import java.io.*;
import java.lang.*;

class GFG {

    public static void main(String args[]) {
        int arr[] = { 10, 20, 10, 30 };
        int n = arr.length;
        int k = 2;

        System.out.print(minPages(arr, n, k));
    }

    public static int sum(int arr[], int b, int e) {
        int s = 0;
        for (int i = b; i <= e; i++)
            s += arr[i];
        return s;
    }

    public static int minPages(int arr[], int n, int k) {
        if (k == 1)
            return sum(arr, 0, n - 1);
        if (n == 1)
            return arr[0];
        int res = Integer.MAX_VALUE;
        for (int i = 1; i < n; i++) {
            res = Math.min(res, Math.max(minPages(arr, i, k - 1), sum(arr, i, n - 1)));
        }
        return res;
    }
}

Allocate Minimum Pages (DP Solution)

import java.util.*;
import java.io.*;
import java.lang.*;

class GFG { 
    
    public static void main(String args[]) 
    { 
        int arr[]={10,20,10,30};
        int n=arr.length;
        int k=2;
        
    	System.out.print(minPages(arr,n,k)); 
    } 
    
    public static int sum(int arr[],int b, int e){
        int s=0;
        for(int i=b;i<=e;i++)
            s+=arr[i];
        return s;
    }
    
    public static int minPages(int arr[],int n, int k){
        int[][] dp=new int[k+1][n+1];
        for(int i=1;i<=n;i++)
            dp[1][i]=sum(arr,0,i-1);
        for(int i=1;i<=k;i++)
            dp[i][1]=arr[0];
            
        for(int i=2;i<=k;i++){
            for(int j=2;j<=n;j++){
                int res=Integer.MAX_VALUE;
                for(int p=1;p<j;p++){
                    res=Math.min(res,Math.max(dp[i-1][p],sum(arr,p,j-1)));
                }
                dp[i][j]=res;
            }
        }
        return dp[k][n];
    }
} 

Last updated