Dynamic Programming

Introduction to dynamic programming

 

what is the result of

1+1+1+1+1+1+1+1

 

Answer is Eight

 

If we add another +1 to the expression above the output is Nine

 

We are able to calculate faster for additional +1 because we memorized the previous result 

 

So In dynamic programming we remember stuff to save time later

If you have sloved a problem with given input than save the result for future reference to avoid solving the same problem again and again

Essence of Dynamic Programming

Components of Dynamic Programming

 

  •  Recursion
  • Memoization

 

 

Characteristics of Dynamic Programming

  • Optimal Substructure property
    • A given problem has optimal substructure property, If an Optimal solution of the given problem can be obtained by using the optimal solution of its subproblems.
    • fib(n) = fib(n-1) + fib(n-2) if n>1
  • Overlapping Subproblems
    • Subproblems are a subset of the original problem. Any problem has overlapping subproblems, if finding its solution requires solving the same problem again and again.

Overlapping sub problems

Dynamic Programming Methods

  • Top-down (Memoization)
    • It is similar approach to recursion as it looks for value in the table first which acts as a cache before computing solutions.
    • If the solution is found than the result will be taken otherwise the problem will be solved and result is stored for the future use.
  • Bottom-up (Tabulation)
    • Tabulation is the opposite of top-down approach and avoids recursion
    • In this approach we solve the problem in bottom up manner by solving all the related sub problems first.

Technique to Solve DP problems

  • To solve a dynamic problem we ca use the fast method
    • Find a recursive solution
    • Analyse the solution (Look for overlapping problems)
    • Save the result for future (Use array for caching purpose)
    • Tweek the solution to make it more powerful by eliminating recursion overhead. (Known as bottom up approach)

Fibonacci number

Write an efficient program to find nth Fibonacci number ?

  • a fibonacci series looks like 0,1,1,2,3,5,8,13,21....

Recursive Solution

public static int fib(int n) {
        if (n < 2)
            return n;
        return fib(n - 1) + fib(n - 2);
    }

Memoization in recursive solution

public static int fib(int n, int[] cache) {
        if (n < 2) {
            return n;
        }
        if (cache[n] != 0) {
            return cache[n];
        }
        return cache[n] = fib(n - 1, cache) + fib(n - 2, cache);
    }

Efficient Bottom up approach

public static int fibTabulation(int n) {
        int[] cache = new int[n + 1];
        cache[0] = 0;
        cache[1] = 1;
        for (int i = 2; i < cache.length; i++) {
            cache[i] = cache[i - 1] + cache[i - 2];
        }
        return cache[n];
    }

Eliminating caching

public static int fibEffec(int n) {
        if(n<2){
            return n;
        }
        int first = 0;
        int second = 1;
        int sum = 0;
        for (int i = 2; i < n + 1; i++) {
            sum = first + second;
            first = second;
            second = sum;
        }
        return sum;
    }

Complete Program

package com.algo.DP;

public class Demo1 {

    public static void main(String[] args) {
        int n = 4;
        int[] cache = new int[n + 1];
        System.out.println(fib(n));
        System.out.println(fib(n, cache));
        System.out.println(fibTabulation(n));
        System.out.println(fibEffec(n));
    }

    public static int fibEffec(int n) {
        if(n<2){
            return n;
        }
        int first = 0;
        int second = 1;
        int sum = 0;
        for (int i = 2; i < n + 1; i++) {
            sum = first + second;
            first = second;
            second = sum;
        }
        return sum;
    }

    public static int fibTabulation(int n) {
        int[] cache = new int[n + 1];
        cache[0] = 0;
        cache[1] = 1;
        for (int i = 2; i < cache.length; i++) {
            cache[i] = cache[i - 1] + cache[i - 2];
        }
        return cache[n];
    }

    public static int fib(int n) {
        if (n < 2)
            return n;
        return fib(n - 1) + fib(n - 2);
    }

    public static int fib(int n, int[] cache) {
        if (n < 2) {
            return n;
        }
        if (cache[n] != 0) {
            return cache[n];
        }
        return cache[n] = fib(n - 1, cache) + fib(n - 2, cache);
    }
}

Staircase problem

A child is climbing up a the staircase with n steps and hop either 1 step or 2 step at a time.

Implement a method to count how many possible ways the child can climb up the stairs.

Recursive Solution

static int stairCaseSolution(int n) {
        if (n < 0) {
            return 0;
        }
        if (n == 0) {
            return 1;
        }
        return stairCaseSolution(n - 1) + stairCaseSolution(n - 2);
    }

Recursive Solution with caching (Memoization)

static int stairCaseSolution(int n, int[] arr) {
        if (n < 0) {
            return 0;
        }
        if (n == 0) {
            return 1;
        }
        if (arr[n] != 0) {
            return arr[n];
        }
        return arr[n] = stairCaseSolution(n - 1, arr) + stairCaseSolution(n - 2, arr);
    }

Bottom Up approach (Tabulation )

static int stairCaseBottomUpSolution(int n, int[] arr) {
        arr[0] = 1;
        arr[1] = 1;
        for (int i = 2; i <= n; i++) {
            arr[i] = arr[i - 1] + arr[i - 2];
        }
        return arr[n];
    }

Tabulation without caching

static int stairCaseBottomUpSolutionWithoutCache(int n) {
        int first = 1, second = 1, sum = 0;

        for (int i = 2; i <= n; i++) {
            sum = first + second;
            first = second;
            second = sum;

        }
        return sum;
    }

House Robber problem

  • You are a professional robber planning to rob the house along a street. 
  • Each house has a certain amount of money stashed.
  • The only constraint stopping you for robbing each of them is that adjacent houses have security systems connected and it will be automatically contact the police if two adjacent houses were broken into the same night.
  • Given a list of non negative integers represent the amount of money you can rob tonight without alerting the police 
  • Sample 1
    • input  : {2,7,9,3,1}
    • rob house 1,3 and 5
    • output : 12

 

 

  • Sample 2
    • input : {5,3,4,11,2}
    • rob house : 1 and 4
    • output : 16
  • Case 1 [ Rob the current house ]: 
    • if the current ith house is selected for robbery it means     (i-1)th and (i+1)th house can't be robbed but can safely proceed to (i-2)th and (i+2)th.
    • ith_house _is_selected = current_house_value + rob(i-2)
  • Case 2 [ Do not rob the current house]:
    • if ith house is not robbed it means robber will get all the possible money of (i-1)th and (i+1)th house and so on.
    • ith_house_is_not_selected = rob(i-1)

Recursive Approach

static int robCache(int[] arr, int n, int[] cache) {
        if (n < 0) {
            return 0;
        }
        if (cache[n] != 0) {
            return cache[n];
        }
        int ith_house_selected = robCache(arr, n - 2, cache) + arr[n];
        int ith_house_not_selected = robCache(arr, n - 1, cache);
        return cache[n] = Math.max(ith_house_selected, ith_house_not_selected);
    }
static int houseRobberBottomUpSolution(int[] arr, int[] cache) {
        cache[0] = arr[0];
        cache[1] = Math.max(arr[0], arr[1]);
        for (int i = 2; i < arr.length; i++) {
            cache[i]=Math.max(cache[i-1],cache[i-2]+arr[i]);
        }
        return cache[arr.length-1];
    }

Memoization

Tabulation

static int houseRobberBottomUpSolution(int[] arr, int[] cache) {
        cache[0] = arr[0];
        cache[1] = Math.max(arr[0], arr[1]);
        for (int i = 2; i < arr.length; i++) {
            cache[i]=Math.max(cache[i-1],cache[i-2]+arr[i]);
        }
        return cache[arr.length-1];
    }

Tabulation without Caching

  static int houseRobberBottomUpSolutionWithoutCache(int[] arr) {
        int prev2 = arr[0];
        int prev1 = Math.max(arr[0], arr[1]);
        for (int i = 2; i < arr.length; i++) {
            int tmp = prev1;
            prev1 = Math.max(prev2 + arr[i], prev1);
            prev2 = tmp;
        }
        return prev1;
    }
package com.algo.DP;

public class HouseRobberProblem {

    public static void main(String[] args) {

        int[] arr = {2, 45, 8, 7, 98, 24};
        int[] cache = new int[arr.length + 1];
        System.out.println(rob(arr, arr.length - 1));
        System.out.println(robCache(arr, arr.length - 1, cache));
        System.out.println(houseRobberBottomUpSolution(arr,cache));
        System.out.println(houseRobberBottomUpSolutionWithoutCache(arr));

    }

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

        if (n < 0) {
            return 0;
        }
        int ith_house_selected = rob(arr, n - 2) + arr[n];
        int ith_house_not_selected = rob(arr, n - 1);
        return Math.max(ith_house_selected, ith_house_not_selected);
    }

    static int robCache(int[] arr, int n, int[] cache) {
        if (n < 0) {
            return 0;
        }
        if (cache[n] != 0) {
            return cache[n];
        }
        int ith_house_selected = robCache(arr, n - 2, cache) + arr[n];
        int ith_house_not_selected = robCache(arr, n - 1, cache);
        return cache[n] = Math.max(ith_house_selected, ith_house_not_selected);
    }

    static int houseRobberBottomUpSolution(int[] arr, int[] cache) {
        cache[0] = arr[0];
        cache[1] = Math.max(arr[0], arr[1]);
        for (int i = 2; i < arr.length; i++) {
            cache[i]=Math.max(cache[i-1],cache[i-2]+arr[i]);
        }
        return cache[arr.length-1];
    }

    static int houseRobberBottomUpSolutionWithoutCache(int[] arr) {
        int prev2 = arr[0];
        int prev1 = Math.max(arr[0], arr[1]);
        for (int i = 2; i < arr.length; i++) {
            int tmp = prev1;
            prev1 = Math.max(prev2 + arr[i], prev1);
            prev2 = tmp;
        }
        return prev1;
    }
}

Complete Program

Longest Common substring

  • Given two strings S1 and S2, find the length of the longest common substring which is common in both the strings.
  • Input : 
    • S1 : JavaProgrammingLanguage
    • S2 : JavaLanguage
  • Output : 8

 

static int longestCommonSubString(char[] str1, char[] str2, int m, int n, int lcsCount) {
        if (m <= 0 || n <= 0) {
            return lcsCount;
        }
        int lcsCount1 = lcsCount;
        if (str1[m - 1] == str2[n - 1]) {
            lcsCount1 = longestCommonSubString(str1, str2, m - 1, n - 1, lcsCount + 1);
        }
        int lcsCount2 = longestCommonSubString(str1, str2, m, n - 1, 0);
        int lcsCount3 = longestCommonSubString(str1, str2, m - 1, n, 0);
        return Math.max(lcsCount1, Math.max(lcsCount2, lcsCount3));
    }

Recursive Solution

Recursive Solution with Caching

static int longestCommonSubStringWithCaching(char[] str1, char[] str2, int m, int n, int lcsCount, int cache[][][]) {
        if (m <= 0 || n <= 0) {
            return lcsCount;
        }
        if (cache[m][n][lcsCount] != 0) {
            return cache[m][n][lcsCount];
        }
        int lcsCount1 = lcsCount;
        if (str1[m - 1] == str2[n - 1]) {
            lcsCount1 = longestCommonSubStringWithCaching(str1, str2, m - 1, n - 1, lcsCount + 1, cache);
        }
        int lcsCount2 = longestCommonSubStringWithCaching(str1, str2, m, n - 1, 0, cache);
        int lcsCount3 = longestCommonSubStringWithCaching(str1, str2, m - 1, n, 0, cache);
        return cache[m][n][lcsCount] = Math.max(lcsCount1, Math.max(lcsCount2, lcsCount3));

    }
 static int longestCommonSubStringBottomUpSolution(char[] str1, char[] str2, int m, int n) {
        int result = 0;
        int[][] memo = new int[m + 1][n + 1];

        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                if (i == 0 || j == 0) {
                    memo[i][j] = 0;
                } else if (str1[i - 1] == str2[j - 1]) {
                    memo[i][j] = memo[i - 1][j - 1] + 1;
                    result = Math.max(memo[i][j], result);
                } else {
                    memo[i][j] = 0;
                }
            }
        }
        return result;
    }

Bottom Up approach

Complete Program

package com.algo.DP;

public class LongestCommonSubStringProblem {

    public static void main(String[] args) {
        String str = "JavaProgrammingLanguage";
        String str2 = "JavaLanguage";
//        String str = "JavaProgram";
//        String str2 = "JavaProgram";
        int m = str.length();
        int n = str2.length();
        int[][][] cache = new int[m + 1][n + 1][Math.max(m, n) + 1];
        System.out.println(longestCommonSubString(str.toCharArray(), str2.toCharArray(), str.length(), str2.length(), 0));
        System.out.println(longestCommonSubStringWithCaching(str.toCharArray(), str2.toCharArray(), str.length(), str2.length(), 0, cache));
        System.out.println(longestCommonSubStringBottomUpSolution(str.toCharArray(), str2.toCharArray(), str.length(), str2.length()));
    }


    static int longestCommonSubStringBottomUpSolution(char[] str1, char[] str2, int m, int n) {
        int result = 0;
        int[][] memo = new int[m + 1][n + 1];
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                if (i == 0 || j == 0) {
                    memo[i][j] = 0;
                } else if (str1[i - 1] == str2[j - 1]) {
                    memo[i][j] = memo[i - 1][j - 1] + 1;
                    result = Math.max(memo[i][j], result);
                } else {
                    memo[i][j] = 0;
                }
            }
        }
        return result;
    }

    static int longestCommonSubStringWithCaching(char[] str1, char[] str2, int m, int n, int lcsCount, int cache[][][]) {
        if (m <= 0 || n <= 0) {
            return lcsCount;
        }
        if (cache[m][n][lcsCount] != 0) {
            return cache[m][n][lcsCount];
        }
        int lcsCount1 = lcsCount;
        if (str1[m - 1] == str2[n - 1]) {
            lcsCount1 = longestCommonSubStringWithCaching(str1, str2, m - 1, n - 1, lcsCount + 1, cache);
        }
        int lcsCount2 = longestCommonSubStringWithCaching(str1, str2, m, n - 1, 0, cache);
        int lcsCount3 = longestCommonSubStringWithCaching(str1, str2, m - 1, n, 0, cache);
        return cache[m][n][lcsCount] = Math.max(lcsCount1, Math.max(lcsCount2, lcsCount3));

    }

    static int longestCommonSubString(char[] str1, char[] str2, int m, int n, int lcsCount) {
        if (m <= 0 || n <= 0) {
            return lcsCount;
        }
        int lcsCount1 = lcsCount;
        if (str1[m - 1] == str2[n - 1]) {
            lcsCount1 = longestCommonSubString(str1, str2, m - 1, n - 1, lcsCount + 1);
        }
        int lcsCount2 = longestCommonSubString(str1, str2, m, n - 1, 0);
        int lcsCount3 = longestCommonSubString(str1, str2, m - 1, n, 0);
        return Math.max(lcsCount1, Math.max(lcsCount2, lcsCount3));
    }
}

Longest Common Subsequence

  • Given two strings S1 and S2, find the length of the longest common subsequence which is common in both the strings
  • Input : 
    • S1 : ACEDBFD
    • S1 : AECDF
  • Output : 4
  • Explanation : The longest common subsequence is ACDF therefore the length is 4.

Algorithm :

  • Case 1 : If character X[i] matches with  Y[i], We can recursively match for remaining characters
  • Case 2 : If character of both the strings are different, we start two new recursive calls by skipping one character separately  from each String.

 

Recursive Solution

static int longestCommonSubSequenceRecursiveSolution(char[] str1, char[] str2, int m, int n) {
        if (m <= 0 || n <= 0) {
            return 0;
        }
        if (str1[m - 1] == str2[n - 1]) {
            return 1 + longestCommonSubSequenceRecursiveSolution(str1, str2, m - 1, n - 1);
        }
        return Math.max(
                longestCommonSubSequenceRecursiveSolution(str1, str2, m, n - 1),
                longestCommonSubSequenceRecursiveSolution(str1, str2, m - 1, n));

    }

Recursive Solution with Caching (Memoization)

static int longestCommonSubSequenceRecursiveSolutionWithCache(char[] str1, char[] str2, int m, int n, int[][] cache) {
        if (m <= 0 || n <= 0) {
            return 0;
        }
        if (cache[m][n] != 0) {
            return cache[m][n];
        }

        if (str1[m - 1] == str2[n - 1]) {
            return 1 + longestCommonSubSequenceRecursiveSolutionWithCache(str1, str2, m - 1, n - 1, cache);
        }

        return cache[m][n] = Math.max(
                longestCommonSubSequenceRecursiveSolutionWithCache(str1, str2, m, n - 1, cache),
                longestCommonSubSequenceRecursiveSolutionWithCache(str1, str2, m - 1, n, cache)
        );

    }
 static int longestCommonSubSequenceBottomUpSolution(char[] str1, char[] str2, int m, int n) {
        int[][] memo = new int[m + 1][n + 1];
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                if (i == 0 || j == 0) {
                    memo[i][j] = 0;
                } else if (str1[i - 1] == str2[j - 1]) {
                    memo[i][j] = memo[i - 1][j - 1] + 1;
                } else {
                    memo[i][j] = Math.max(memo[i - 1][j], memo[i][j - 1]);
                }
            }
        }
        return memo[m][n];
    }

Tabulation Solution

package com.algo.DP;

public class LongestCommonSubSequenceProblem {

    public static void main(String[] args) {
        String str = "Javaaid";
        String str2 = "Javaid";
        int m = str.length();
        int n = str2.length();
        int[][] cache = new int[m + 1][n + 1];
//        System.out.println(longestCommonSubSequenceRecursiveSolution(str.toCharArray(), str2.toCharArray(), m, n));
//        System.out.println(longestCommonSubSequenceRecursiveSolutionWithCache(str.toCharArray(), str2.toCharArray(), m, n, cache));
        System.out.println(longestCommonSubSequenceBottomUpSolution(str.toCharArray(), str2.toCharArray(), m, n));
    }

    static int longestCommonSubSequenceBottomUpSolution(char[] str1, char[] str2, int m, int n) {
        int[][] memo = new int[m + 1][n + 1];
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                if (i == 0 || j == 0) {
                    memo[i][j] = 0;
                } else if (str1[i - 1] == str2[j - 1]) {
                    memo[i][j] = memo[i - 1][j - 1] + 1;
                } else {
                    memo[i][j] = Math.max(memo[i - 1][j], memo[i][j - 1]);
                }
            }
        }
        return memo[m][n];
    }

    static int longestCommonSubSequenceRecursiveSolutionWithCache(char[] str1, char[] str2, int m, int n, int[][] cache) {
        if (m <= 0 || n <= 0) {
            return 0;
        }
        if (cache[m][n] != 0) {
            return cache[m][n];
        }

        if (str1[m - 1] == str2[n - 1]) {
            return 1 + longestCommonSubSequenceRecursiveSolutionWithCache(str1, str2, m - 1, n - 1, cache);
        }

        return cache[m][n] = Math.max(
                longestCommonSubSequenceRecursiveSolutionWithCache(str1, str2, m, n - 1, cache),
                longestCommonSubSequenceRecursiveSolutionWithCache(str1, str2, m - 1, n, cache)
        );

    }

    static int longestCommonSubSequenceRecursiveSolution(char[] str1, char[] str2, int m, int n) {
        if (m <= 0 || n <= 0) {
            return 0;
        }
        if (str1[m - 1] == str2[n - 1]) {
            return 1 + longestCommonSubSequenceRecursiveSolution(str1, str2, m - 1, n - 1);
        }
        return Math.max(
                longestCommonSubSequenceRecursiveSolution(str1, str2, m, n - 1),
                longestCommonSubSequenceRecursiveSolution(str1, str2, m - 1, n));

    }

}

Complete Program

0-1 Knapsack Problem

  • Given a Set S of n items each with its own value V and Weight W for all 1<=i<=n and maximum knapsack capacity C, compute the maximum value of the items that you can carry. You cannot take fractions of items.
  • Sample
    • val {150, 300, 200}
    • wt {1,4,3}
package com.algo.DP;

public class ZeroOneKnapsackProblem {
    
    public static void main(String[] args) {
        int[] value = {150, 300, 200};
        int[] weight = {1, 4, 3};
        int capacity = 4;
        System.out.println(zeroOneKnapsackProblem(value,weight,capacity));
    }

    public static int zeroOneKnapsackProblem(int[] value, int[] weight, int capacity) {
        int n = value.length;
        int[][] memo = new int[n + 1][capacity + 1];
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= capacity; j++) {
                if (i == 0 || j == 0) {
                    memo[i][j] = 0;
                } else if (weight[i - 1] > j) {
                    memo[i][j] = memo[i - 1][j];
                }else{
                    memo[i][j]=Math.max(value[i-1]+memo[i-1][j-weight[i-1]],memo[i-1][j]);
                }
            }
        }
        return memo[n][capacity];
    }
}

Dynamic Programming for Java Developers Part 2

Write an efficient program to find the sum of contiguous subarray within a one-dimensional array of numbers that has the largest sum. 
4 3 -2 6 7 -10 -10 4 5 9
  • 4 -> 4
  • 7 -> 4,3
  • 5 -> 4,3,-2
  • 11-> 4,3,-2,6
  • 18 -> 4,3,-2,6,7
  • 8 -> 4,3,-2,6,7,-10
  • -2 -> 4,3,-2,6,7,-10,-10
  • 4 -> 4
  • 9 -> 4,5
  • 18 -> 4,5,9
  • 15-> 4,5,9,-3
  • 19-> 4,5,9,-3,4
  • 26-> 4,5,9,-3,4,7
  • 35->4,5,9,-3,4,7,9
  • 4 -> 4
  • 7 -> 4,3
  • 5 -> 4,3,-2
  • 11-> 4,3,-2,6
  • 18 -> 4,3,-2,6,7
  • 19-> 4,5,9,-3,4
  • 26-> 4,5,9,-3,4,7
  • 35->4,5,9,-3,4,7,9
-3 4 7 9

Kadane's Theorm

Current Best

Overall Best

package com.algo.DP;

public class KadaneAlgorithm {
    public static void main(String[] args) {
        int[] arr = {4, 3, -2, 6, -12, 7, -1, 6};
        System.out.println(maxNumberInArray(arr));

    }

    public static int maxNumberInArray(int[] arr) {
        int currentMax = arr[0];
        int maxSoFar = arr[0];

        for (int i = 1; i < arr.length; i++) {
            currentMax = currentMax + arr[i];
            if (currentMax < arr[i]) {
                currentMax = arr[i];
            }
            if (maxSoFar < currentMax) {
                maxSoFar = currentMax;
            }
        }
        return maxSoFar;
    }
}

The Longest Increasing Subsequence (LIS) problem is to find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order. For example, the length of LIS for {10, 22, 9, 33, 21, 50, 41, 60, 80} is 6 and LIS is {10, 22, 33, 50, 60, 80}. 

Longest Increasing Subsequence

10 ​22 9 33 21 50 41 60 80 1
1 2 1 3 2 4 4 5 6 1
- - - - - - - - - -
10 10 9 10  10 10 10 10 10 3
22 22 21 22 22 22 22
33 33 33 33 33
50 41 50 50
60 60
80

Elements

Count

package com.algo.DP;

import java.util.Arrays;

public class LongestIncreasingSequence {

    public static void main(String[] args) {
        int[] arr = {10,22,9,33,21,50,41,60,80,1};
        System.out.println(findLIS(arr));
    }


    public static int findLIS(int[] arr) {
        int[] dp = new int[arr.length];
        dp[0] = 1;
        int maxo = 0;
        for (int i = 1; i < arr.length; i++) {
            int max = 0;
            for (int j = 0; j < i; j++) {
                if (arr[i] > arr[j] && dp[j] > max) {
                        max = dp[j];
                }
                dp[i] = max + 1;
            }
            if (dp[i] > maxo) {
                maxo = dp[i];
            }
            System.out.println(Arrays.toString(dp));
        }
        return maxo;
    }
}

Given a set of non-negative integers, and a value sum, determine if there is a subset of the given set with sum equal to given sum

 

example

 

Input: set[] = {3, 34, 4, 12, 5, 2}, sum = 9
Output: True  
There is a subset (4, 5) with sum 9.

Input: set[] = {3, 34, 4, 12, 5, 2}, sum = 30
Output: False
There is no subset that add up to 30.

Target Sum Subset

1 2 3 4 5 6 7 8 9 10
F F F F F F F F F F
F F F T F F F F F F
F T F T F T F F F F
F T F T F T T F T F
T T T T T T T T T T
T T T T T T T T T T
0
X T
4 T
2 T
7 T
1 T
3 T

Input :

Array = {4,5,7,1,3}

Sum=10

package com.algo.DP;

public class TargetSubSets {

    public static void main(String[] args) {
        int[] arr = {4, 2, 7, 1, 3};
        int target = 59;
        System.out.println(targetSubset(arr, target));
    }

    public static boolean targetSubset(int[] arr, int target) {
        boolean[][] dp = new boolean[arr.length + 1][target + 1];
        for (int i = 0; i < dp.length; i++) {
            for (int j = 0; j < dp[i].length; j++) {
                if (i == 0 && j == 0) {
                    dp[i][j] = true;
                } else if (i == 0) {
                    dp[i][j] = false;
                } else if (j == 0) {
                    dp[i][j] = true;
                } else {
                    if (dp[i - 1][j] == true) {
                        dp[i][j] = true;
                    } else {
                        int val = arr[i - 1];
                        if (val <= j) {
                                if(dp[i-1][j-val]==true){
                                    dp[i][j]=true;
                                }
                        }
                    }
                }
            }
        }
        return dp[arr.length][target];
    }
}

Given a gold mine of n*m dimensions. Each field in this mine contains a positive integer which is the amount of gold in tons. Initially the miner is at first column but can be at any row. He can move only (right->,right up /,right down\) that is from a given cell, the miner can move to the cell diagonally up towards the right or right or diagonally down towards the right. Find out maximum amount of gold he can collect.

Gold Mine Problem

- - - - - -
0 1 4 2 8 2
4 3 6 5 0 4
1 2 4 1 4 6
2 0 7 3 2 2
3 1 5 9 2 4
2 7 0 8 5 1
- - - - - -
26 24 21 14 12 2
31 26 23 17 6 4
28 27 21 11 10 6
29 25 25 13 8 2
33 26 23 18 6 4
32 30 18 17 9 1
package com.algo.DP;

public class GoldMine {

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

        System.out.println(goldMine(arr));
    }

    public static int goldMine(int[][] arr) {
        int[][] dp = new int[arr.length][arr.length];
        for (int j = arr.length - 1; j >= 0; j--) {
            for (int i = arr.length - 1; i >= 0; i--) {
                if (j == arr.length - 1) {
                    dp[i][j] = arr[i][j];
                } else if (i == 0) {
                    dp[i][j] = arr[i][j] + Math.max(dp[i + 1][j + 1], dp[i][j + 1]);
                } else if (i == arr.length - 1) {
                    dp[i][j] = arr[i][j] + Math.max(dp[i - 1][j + 1], dp[i][j + 1]);
                } else {
                    dp[i][j] = arr[i][j] + Math.max(dp[i][j + 1], Math.max(dp[i - 1][j + 1], dp[i + 1][j + 1]));
                }
            }
        }
        int max = dp[0][0];
        for (int i = 1; i < dp.length; i++) {
            if (dp[i][0] > max) {
                max = dp[i][0];
            }
        }
        return max;
    }
}

The cost of a stock on each day is given in an array, find the max profit that you can make by buying and selling in those days. For example, if the given array is {100, 180, 260, 310, 40, 535, 695}, the maximum profit can earn by buying on day 0, selling on day 3. Again, buy on day 4 and sell on day 6. If the given array of prices is sorted in decreasing order, then profit cannot be earned at all.

Stock Buy and Sell Problem

6

5

4

3

2

1

0

7

1 2 1 2 3 2 3 4 3 4
5

1

2

8

7

6

5

4

3

10

9

package com.algo.DP;

public class StockBuyAndSell {

    public static void main(String[] args) {
        int arr[] = {1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5};
        System.out.println(stockBuyAndSell(arr));
    }

    public static int stockBuyAndSell(int arr[]) {
        int bd = 0;
        int sd = 0;
        int profit = 0;
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] >= arr[i - 1]) {
                sd++;
            } else {
                profit += arr[sd] - arr[bd];
                bd = sd = i;
            }
        }
        profit += arr[sd] - arr[bd];
        return profit;
    }
}

Given a “2 x n” board and tiles of size “2 x 1”, count the number of ways to tile the given board using the 2 x 1 tiles. A tile can either be placed horizontally i.e., as a 1 x 2 tile or vertically i.e., as 2 x 1 tile.

Tiling Problem

2 x 1

2 x 2

2 x 3

2 x 4

2 x 5

Size Ways
1 1
2 2
3 3
4 5
5 8
package com.algo.DP;

public class TilingDominoes {

    public static void main(String[] args) {
        int n = 3;
        System.out.println(tilingDominoes(n));

    }

    public static int tilingDominoes(int n) {
        if(n<=2){
            return n;
        }
        int first = 1;
        int second = 2;
        int ways = 0;
        for (int i = 3; i <= n; i++) {
            ways = first + second;
            first = second;
            second = ways;
        }
        return ways;
    }
}

Given a rod of length n inches and an array of prices that includes prices of all pieces of size smaller than n. Determine the maximum value obtainable by cutting up the rod and selling the pieces. For example, if the length of the rod is 8 and the values of different pieces are given as the following, then the maximum obtainable value is 22 (by cutting in two pieces of lengths 2 and 6) 

length   | 1   2   3   4   5   6   7   8  
--------------------------------------------
price    | 1   5   8   9  10  17  17  20

Rod Cutting Problem

Cost N 1 5 8 9 10 17 17 20
Wood Length 0 1 2 3 4 5 6 7 8
Best Cost 0 1 5 8 10 13 17 18 22
Combination (Best)  0  1- 0 2-0 3-0 2-2 2-3 6-0 6-1 2-6
package com.algo.DP;

import java.util.Arrays;

public class RodCutting {

    public static void main(String[] args) {
        int[] prices = {1, 5, 8, 9, 10};
        System.out.println(rodCutting(prices));
    }

    public static int rodCutting(int[] prices) {
        int[] np = new int[prices.length + 1];
        for (int i = 0; i < prices.length; i++) {
            np[i + 1] = prices[i];
        }
        int[] dp = new int[np.length];
        dp[0] = 0;
        dp[1] = np[1];
        for (int i = 2; i < dp.length; i++) {
            dp[i] = np[i];
            int li = 1;
            int ri = i - 1;
            while (li <= ri) {
                if (dp[i] < dp[li] + dp[ri]) {
                    dp[i] = dp[li] + dp[ri];
                }
                li++;
                ri--;
            }
        }
        System.out.println(Arrays.toString(dp));
        return dp[dp.length - 1];
    }
}

The following is a description of the instance of this famous puzzle involving n=2 eggs and a building with k=36 floors.
Suppose that we wish to know which stories in a 36-story building are safe to drop eggs from, and which will cause the eggs to break on landing. We make a few assumptions:
…..An egg that survives a fall can be used again.
…..A broken egg must be discarded.
…..The effect of a fall is the same for all eggs.
…..If an egg breaks when dropped, then it would break if dropped from a higher floor.
…..If an egg survives a fall then it would survive a shorter fall.
…..It is not ruled out that the first-floor windows break eggs, nor is it ruled out that the 36th-floor do not cause an egg to break.
If only one egg is available and we wish to be sure of obtaining the right result, the experiment can be carried out in only one way. Drop the egg from the first-floor window; if it survives, drop it from the second-floor window. Continue upward until it breaks. In the worst case, this method may require 36 droppings. Suppose 2 eggs are available. What is the least number of egg-droppings that is guaranteed to work in all cases?

7 f 

3 e 

 Here we need to find the minimum attempts in which we will find the critical floor. Critical floor  (i.e from where egg will break).

    Base cases

    f=0 -> 0

    f=1-> 1

    e=0 -> X

    e=1 -> f

Egg Dropping  Problem

e|f

Survived

Broke

e|f-k

e-1|k-1

kth Floor

7 floors 3 eggs

0 1 2 3 4 5 6 7
0 - - - - - - - -
1 0 1 2 3 4 5 6 7
2 0 1 2 2 3 3 3 4
3 0 1 2 2 3 3 3 3

Floors

Eggs

3,3,3,2,3,3,3

2 E/ 2F

1 F

2 F

Broke

Survive

Broke

Survive

1E/ 0F = 0

2 E/ 1F = 1

1 E/ 1F = 1

2 E/ 0F = 0

Max(1,0)=1

Max(0,1)=1

Min(1,1)+1=2

2E|3F

2E|0F =0

1E|2F=2

2E|1F =1

1E|1F =1

2E|2F=2

1E|0F=0

1F

2F

3F

Broke

Survive

Broke

Survive

Broke

Survive

Max(2,0)=2

Max(1,1)=1

Max(0,2)=2

Min(2,1,2)+1=2

package com.algo.DP;

public class EggDropping {

    public static void main(String[] args) {
        int floors = 7;
        int eggs = 3;
        System.out.println(eggDropping(eggs, floors));;
    }

    public static int eggDropping(int n, int k) {
        int[][] dp = new int[n + 1][k + 1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= k; j++) {
                if (i == 1) {
                    dp[i][j] = j;
                } else if (j == 1) {
                    dp[i][j] = 1;
                } else {
                    int min = Integer.MAX_VALUE;
                    for (int mj = j - 1, pj = 0; mj >= 0; mj--, pj++) {
                        int v1 = dp[i][mj];// egg survive
                        int v2 = dp[i - 1][pj];// egg breaks
                        int val = Math.max(v1, v2);
                        min = Math.min(val, min);
                    }
                    dp[i][j] = min + 1;
                }
            }
        }
        return dp[n][k];
    }
}

Java 9

By Pulkit Pushkarna

Java 9

  • 955