Showing posts with label Dynamic Programming. Show all posts
Showing posts with label Dynamic Programming. Show all posts

Longest Common Subsequence (LCS) algorithm using Dynamic Programming in java

The Longest Common Subsequence (LCS) problem is given with two strings like "ABAZDC" and "BACBAD". LCS is to find their longest common subsequence that appear left-to-right but not necessarily in a contiguous block in both the strings. Here we will see how to achieve Longest Common Subsequence (LCS) algorithm using Dynamic Programming using Java.

Example:
Str1 = "ABAZDC"
Str2 = "BACBAD"

Here the Longest Common Subsequence (LCS) size will be 4 and the Longest Common Subsequence (LCS) will "ABAD".

How to find Longest Common Subsequence (LCS)?

First we need to construct matrix of size str1 and str2 like matrix[str1.length][str2.matrix] as shown below
Longest Common Subsequence (LCS) algorithm using Dynamic Programming in java

Whenever any character matches with both the array then we need to increment the value by 1 and carry on with same comparison for all rows and columns.
Same comparison will be done using recursion and by storing the value to achieve dynamic programming.  


public class LCS {

 public static void main(String[] args) {

  String str1 = "ABAZDC";
  String str2 = "BACBAD";

  LCS obj = new LCS();
  String out = obj.getLCS(str1, str2);

  System.out.println("LCS Length : " + out.length());
  System.out.println("LCS String : " + out);
 }

 public String getLCS(String str1, String str2) {

  /* Array will be updated with the character change order */
  int arr[][] = new int[str1.length()][str2.length()];
  
  /* Calling actual LCS recursive method */
  getLCS(str1, str1.length() - 1, str2, str2.length() - 1, arr);

  return constructLCSString(arr, str1, str2);
 }
 
 /*
  * Constructing the LCS string the generated array arr[]
  */
 public String constructLCSString(int[][] arr, String str1, String str2) {
  
  String lcsString = "";
  
  /* Iterating through arr[] to get the actual LCS string 
   * iterating from bottom to up.
   */
  for (int i = arr.length - 1, j = arr[0].length - 1; (i >= 0 && j >= 0);) {

   if (i == 0) {
    lcsString = str1.charAt(i) + lcsString;
    break;
   } else if (j == 0) {
    lcsString = str2.charAt(j) + lcsString;
    break;
   }

   if (arr[i][j] != arr[i - 1][j] && arr[i][j] != arr[i][j - 1]) {
    lcsString = str1.charAt(i) + lcsString;
    i--;j--;
   } else if (arr[i][j] == arr[i - 1][j]) {
    i--;
   } else if (arr[i][j] == arr[i][j - 1]) {
    j--;
   }
  }
  return lcsString;
 }
 
 
 public int getLCS(String str1, int n, String str2, int m, int arr[][]) {
  if (n == -1 || m == -1)
   return 0;
  
  /*
   * Checking in array for same n, m index and if present returning 
   * the value from array and its Dynamic programming
   */
  if (arr[n][m] != 0)
   return arr[n][m];

  int output = 0;
  if (str1.charAt(n) == str2.charAt(m)) {
   output = 1 + getLCS(str1, n - 1, str2, m - 1, arr);
  } else {
   int tmp1 = getLCS(str1, n - 1, str2, m, arr);
   int tmp2 = getLCS(str1, n, str2, m - 1, arr);
   output = tmp1 > tmp2 ? tmp1 : tmp2;
  }
  /* Memorize the output on array to use for similar recursive call */
  arr[n][m] = output;
  return output;
 }
}

OUTPUT:


LCS Length : 4
LCS String : ABAD

Dynamic Programming - Find nth Fibonacci number

Dynamic Programming (DP) is an algorithmic that solves a given complex problem by breaking it into subproblems and stores the results of subproblems to avoid computing the same results again for another subproblems. Just make use of the previously computed result by storing and by this complexity will be reduced.
Usually we used to write a recursive call for getting list of Fibonacci series or to get the nth element in Fibonacci series. Here we will see simple recursive method for getting nth Fibonacci number with and without dynamic programming and latter will compare the benefits of using DP.
Dynamic Programming - Find nth Fibonacci number


Find nth Fibonacci number using recursive:


public class Fibonacci {
 
 static int i = 0;
 
 public static void main(String[] args) {
  int n = 10;
  int val = fibo(n);
  System.out.println("No. of recursive calls : "+i);
  System.out.println(n +"th Fibonacci number : "+val);
  
 }
 
 public static int fibo(int n) {
  System.out.println("CALL ::: "+ (++i) + " - n: "+n);
  if(n<=2) {
   return 1;
  }
  else {
   int f = fibo(n-1) + fibo(n-2);
   return f;
  }
 }
}


OUTPUT:


CALL ::: 1 - n: 10
CALL ::: 2 - n: 9
CALL ::: 3 - n: 8
CALL ::: 4 - n: 7
CALL ::: 5 - n: 6
CALL ::: 6 - n: 5
CALL ::: 7 - n: 4
CALL ::: 8 - n: 3
CALL ::: 9 - n: 2
CALL ::: 10 - n: 1
CALL ::: 11 - n: 2
CALL ::: 12 - n: 3
CALL ::: 13 - n: 2
CALL ::: 14 - n: 1
CALL ::: 15 - n: 4
CALL ::: 16 - n: 3
CALL ::: 17 - n: 2
CALL ::: 18 - n: 1
CALL ::: 19 - n: 2
CALL ::: 20 - n: 5
CALL ::: 21 - n: 4
CALL ::: 22 - n: 3
CALL ::: 23 - n: 2
CALL ::: 24 - n: 1
CALL ::: 25 - n: 2
CALL ::: 26 - n: 3
CALL ::: 27 - n: 2
CALL ::: 28 - n: 1
CALL ::: 29 - n: 6
CALL ::: 30 - n: 5
CALL ::: 31 - n: 4
CALL ::: 32 - n: 3
CALL ::: 33 - n: 2
CALL ::: 34 - n: 1
CALL ::: 35 - n: 2
CALL ::: 36 - n: 3
CALL ::: 37 - n: 2
CALL ::: 38 - n: 1
CALL ::: 39 - n: 4
CALL ::: 40 - n: 3
CALL ::: 41 - n: 2
CALL ::: 42 - n: 1
CALL ::: 43 - n: 2
CALL ::: 44 - n: 7
CALL ::: 45 - n: 6
CALL ::: 46 - n: 5
CALL ::: 47 - n: 4
CALL ::: 48 - n: 3
CALL ::: 49 - n: 2
CALL ::: 50 - n: 1
CALL ::: 51 - n: 2
CALL ::: 52 - n: 3
CALL ::: 53 - n: 2
CALL ::: 54 - n: 1
CALL ::: 55 - n: 4
CALL ::: 56 - n: 3
CALL ::: 57 - n: 2
CALL ::: 58 - n: 1
CALL ::: 59 - n: 2
CALL ::: 60 - n: 5
CALL ::: 61 - n: 4
CALL ::: 62 - n: 3
CALL ::: 63 - n: 2
CALL ::: 64 - n: 1
CALL ::: 65 - n: 2
CALL ::: 66 - n: 3
CALL ::: 67 - n: 2
CALL ::: 68 - n: 1
CALL ::: 69 - n: 8
CALL ::: 70 - n: 7
CALL ::: 71 - n: 6
CALL ::: 72 - n: 5
CALL ::: 73 - n: 4
CALL ::: 74 - n: 3
CALL ::: 75 - n: 2
CALL ::: 76 - n: 1
CALL ::: 77 - n: 2
CALL ::: 78 - n: 3
CALL ::: 79 - n: 2
CALL ::: 80 - n: 1
CALL ::: 81 - n: 4
CALL ::: 82 - n: 3
CALL ::: 83 - n: 2
CALL ::: 84 - n: 1
CALL ::: 85 - n: 2
CALL ::: 86 - n: 5
CALL ::: 87 - n: 4
CALL ::: 88 - n: 3
CALL ::: 89 - n: 2
CALL ::: 90 - n: 1
CALL ::: 91 - n: 2
CALL ::: 92 - n: 3
CALL ::: 93 - n: 2
CALL ::: 94 - n: 1
CALL ::: 95 - n: 6
CALL ::: 96 - n: 5
CALL ::: 97 - n: 4
CALL ::: 98 - n: 3
CALL ::: 99 - n: 2
CALL ::: 100 - n: 1
CALL ::: 101 - n: 2
CALL ::: 102 - n: 3
CALL ::: 103 - n: 2
CALL ::: 104 - n: 1
CALL ::: 105 - n: 4
CALL ::: 106 - n: 3
CALL ::: 107 - n: 2
CALL ::: 108 - n: 1
CALL ::: 109 - n: 2
No. of recursive calls : 109
10th Fibonacci number : 55


If we seen above output we can get to know that just for 10th Fibonacci number total 109 recursive calls made. Also in many cases like Fibo(4), Fibo(5), Fino(3) etc., are multiple times computed for same value. So here we need to use the power of Dynamic Programming to store the computed value and need to reuse the result if same value occurs again. By this we can avoid lot of iterations/recursive call's.

Lets see converting above program to Dynamic Programming by storing the computed value and reusing it again when its need. By this lets find out how many recursive calls made for getting 10th Fibonacci number.

Find nth Fibonacci number using Dynamic Programming:


import java.util.HashMap;

public class Fibonacci {
 
 static int i = 0;
 static HashMap<Integer, Integer> map = new HashMap<>();
 
 public static void main(String[] args) {
  int n = 10;
  int val = fibo(n);
  System.out.println("No. of recursive calls : "+i);
  System.out.println(n +"th Fibonacci number : "+val);
  
 }
 
 public static int fibo(int n) {
  
  if(map.containsKey(n)) 
   return map.get(n);
  
  System.out.println("CALL ::: "+ (++i) + " - n: "+n);
  if(n<=2) {
   map.put(n, 1);
   return 1;
  }
  else {
   int f = fibo(n-1) + fibo(n-2);
   map.put(n, f);
   return f;
  }
 }
}


OUTPUT:


CALL ::: 1 - n: 10
CALL ::: 2 - n: 9
CALL ::: 3 - n: 8
CALL ::: 4 - n: 7
CALL ::: 5 - n: 6
CALL ::: 6 - n: 5
CALL ::: 7 - n: 4
CALL ::: 8 - n: 3
CALL ::: 9 - n: 2
CALL ::: 10 - n: 1
No. of recursive calls : 10
10th Fibonacci number : 55


Now we can compare the no. of recursive calls made my 1st program and 2nd program exactly to get the same output of 10th Fibonacci number. If we see 1st program taken 109 recursive calls and 2nd dynamic program taken only 10 recursive calls for same problem and output.