Dynamic Programming
Ajith Jose
What is Dynamic Programming?
Dynamic Programming is a programming
technique that solves an algorithmic problem
by breaking it recursively into sub-problems.
The sub-problem results are saved in a tabular
format to avoid duplicate computation. The
problem being solved satisfies two properties
• Overlapping Sub-problems
• Optimal Substructure
Fibonacci Number
nth fibonacci number represented by
f(n) = f(n-1) + f(n-2)
f(0) = 0 and f(1) = 1
int fib(int n){
if(n<=1) return n;
return fib(n-1) + fib(n-2);
}
fib(5)
fib(4) fib(3)
fib(3) fib(2) fib(2) fib(1)
fib(2) fib(1) fib(1) fib(0) fib(1) fib(0)
Overlapping Sub-problems
Solutions of same sub-problems are needed again and again.
Memoization (Top-down Approach)
int[] memo;
void initialize(int n){
memo = new int[n];
for(int i=0;i<memo.length;i++){
memo[i]=-1;
}
}
int fib(int n){
if(memo[n] == -1){
if(n<=1){
memo[n] = n;
}else{
memo[n] = fib(n-1) + fib(n-2);
}
}
return memo[n];
}
public void test(){
initialize(25);
System.out.println("20th fibonacci no. is : "+fib(20));
}
Tabulation (Bottom-up Approach)
int fib(int n){
int[] table = new int[n+1];
table[0] = 0; table[1] = 1;
for(int i=2; i<=n; i++){
table[i] = table[i-1] + table[i-2];
}
return table[n];
}
public void test(){
System.out.println("20th fibonacci no. is : "+fib(20));
}
Dynamic
Programming
Fibonacci Number Optimized
int fib(int n){
int a = 0, b= 1, c;
for(int i=2; i<=n; i++){
c = a + b;
a = b;
b = c;
}
return b;
}
Minimum Cost Path Problem
int minCost(int[][] cost, int m, int n){
if(m<0 || n<0){
1 5 3 return Integer.MAX_VALUE;
}
4 8 2 if(m==0 && n==0){
return cost[0][0];
}
1 2 3 return cost[m][n] +
min(minCost(cost, m-1, n-1), minCost(cost, m, n-1), minCost(cost, m-1, n));
}
minCost(m,n) = cost[m][n] + min( minCost(m-1, n-1), minCost(m-1, n), minCost(m, n-1) )
Optimal Substructure
Optimal solution of the given problem can be obtained by using
optimal solutions of its sub-problems.
cost matrix minCost table
1 5 3 6 10 8
4 8 2 5 9 5
1 2 3 1 3 6
int minCost(int[][] cost, int m, int n){
int[][] table = new int[m+1][n+1];
table[0][0] = cost[0][0];
for(int i=1;i<=m;i++)
table[i][0] = table[i-1][0] + cost[i][0];
for(int j=1;j<=n;j++)
table[0][j] = table[0][j-1] + cost[0][j];
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
table[i][j] = cost[i][j] +
min(table[i-1][j-1], table[i][j-1], table[i-1][j]);
return table[m][n];
}
Longest Common Subsequence (LCS)
String Sequence
ABCDEFG
Subsequences
ABC, ABG, BDF, AEG, ACEFG
Longest Common Subsequences
LCS of ABCDGH and AEDFHR
AD, AH, ADH are common subsequences
ADH is an LCS
LCS of AGGTAB and GXTXAYB
GT, AB, GTA, TAB, GTAB are common subsequences
GTAB is an LCS
LCS in UNIX diff
Version 1
A B C D F G H J Q Z
Version 2
A B C D E F G I J K R X Y Z
LCS
A B C D F G J Z
Deletions (-)
H Q
Additions (+)
E I K R X Y
LCS Recursion
Let S1 & S2 be two sequences with lengths m & n
Length of LCS
Case when last character of both S1 & S2 match
LCS(“AGGTAB”, “GXTXAYB”) = 1 + LCS(“AGGTA”, “GXTXAY”)
LCS(S1, S2, m, n) = 1 + LCS(S1, S2, m-1, n-1)
Otherwise,
LCS(“ABCDGH”, “AEDFHR”) = MAX ( LCS(“ABCDG”, “AEDFHR”),
LCS(“ABCDGH”, “AEDFH”) )
LCS(S1, S2, m, n) = MAX(LCS(S1, S2, m-1, n), LCS(S1, S2, m, n-1))
LCS Naive Recursive Solution
int lcs(char[] S1, char[] S2, int m, int n) {
if(m==0 || n==0){
return 0;
}else if(S1[m-1] == S2[n-1]){
return 1 + lcs(S1, S2, m-1, n-1);
}else{
return max(lcs(S1, S2, m, n-1), lcs(S1, S2, m-1, n));
}
}
lcs("AXYT", "AYZX")
lcs("AXY", "AYZX") lcs("AXYT", "AYZ")
lcs("AX", "AYZX") lcs("AXY", "AYZ") lcs("AXY", "AYZ") lcs("AXYT", "AY")
LCS Dynamic Programming Solution
LCS( “ABACD”, “ADCDE”, 5, 5 ) int lcs(char[] S1, char[] S2, int m, int n) {
int[][] L = new int[m+1][n+1];
D 0 1 1 2 3 3
0 1 1 2 2 2 for(int i=0;i<=m;i++)
C
for(int j=0;j<=n;j++){
A 0 1 1 1 1 1 if(i==0 || j==0){
L[i][j] = 0;
B 0 1 1 1 1 1 }
else if(S1[i-1] == S2[j-1]){
A 0 1 1 1 1 1 L[i][j] = 1 + L[i-1][j-1];
}
0 0 0 0 0 0 else{
L[i][j] = max(L[i-1][j], L[i][j-1]);
A D C D E }
}
return L[m][n];
}
LCS Dynamic Programming Solution
LCS( “ABACD”, “ADCDE”, 5, 5 ) String printLCS(char[] S1, char[] S2, int m, int n){
int lcsLength = lcs(S1, S2, m, n);
char[] lcsChars = new char[lcsLength];
D 0 1 1 2 3 3
0 1 1 2 2 2 int i=m, j=n, l=lcsLength-1;
C
while(i>0 && j>0){
A 0 1 1 1 1 1 if(S1[i-1] == S2[j-1]){
lcsChars[l] = S1[i-1];
B 0 1 1 1 1 1 i--;j--;l--;
}else if( L[i-1][j] > L[i][j-1] ){
A 0 1 1 1 1 1 i--;
}else{
0 0 0 0 0 0 j--;
}
A D C D E }
return new String(lcsChars);
A C D
}
Longest Common Substring
lcSubStr( “TABLE”, “STABS”, 5, 5 ) int lcSubStr(char[] S1, char[] S2, int m, int n)
{
int[][] L = new int[m+1][n+1];
S 0 0 0 0 0 0 int maxLength = 0;
B 0 0 0 3 0 0
for(int i=0;i<=m;i++)
0 for(int j=0;j<=n;j++){
A 0 2 0 0 0
if(i==0 || j==0){
T 0 1 0 0 0 0 L[i][j] = 0;
}else if(S1[i-1] == S2[j-1]){
S 0 0 0 0 0 0 L[i][j] = 1 + L[i-1][j-1];
maxLength = max(L[i][j], maxLength);
0 0 0 0 0 0 }else{
L[i][j] = 0;
T A B L E }
}
return maxLength;
}
Longest Increasing Subsequence
int lis(int[] S, int n) {
1 7 2 12 5 15
int[] L = new int[n];
int max = 0;
Initialization for(int i=0;i<n;i++){
L[i] = 1;
1 1 1 1 1 1 }
for(int i=1;i<n;i++)
LIS Length for(int j=0;j<i;j++){
if(S[i] > S[j] && L[i] <= L[j]){
1 2 2 3 3 4 L[i] = L[j]+1;
if(L[i]>max){
max = L[i];
}
}
}
return max;
}
Where did you use Dynamic Programming?
Time Series Pattern Searching
i i
i i i+2
time time
Any distance (Euclidean, A non-linear (elastic) alignment
Manhattan, …) which aligns produces a more intuitive
the i-th point on one time series similarity measure, allowing
with the i-th point on the other similar shapes to match even if
will produce a poor similarity they are out of phase in the
score. time axis.
Dynamic Time Warping
Time Series A
1 is n
m
To find the best alignment
between A and B one needs to
find the path through the grid
P = p1, … , ps , … , pk
ps = (is , js )
which minimizes the total js
distance between them.
P is called a warping function.
Time Series B 1
Warping Window
Warping Window: |is – js| ≤ r, where r > 0
is the window length.
A good alignment path is unlikely to
wander too far from the diagonal.
i
Guarantees that the alignment does not
try to skip different features and gets
stuck at similar features.
Conclusion & Definition Revisited
Dynamic Programming is a programming
technique that solves an algorithmic problem
by breaking it recursively into sub-problems.
The sub-problem results are saved in a tabular
format to avoid duplicate computation. The
problem being solved satisfies two properties
• Overlapping Sub-problems
• Optimal Substructure
Thank You !