DAA UNIT-IV-Dynamic Porgramming
DAA UNIT-IV-Dynamic Porgramming
Syllabus:
1. Optimal Substructure:
A problem has an optimal substructure if an optimal solution to the problem can be
constructed from optimal solutions to its subproblems. For instance, in the shortest path
problem, the shortest path from A to C through B involves the shortest path from A to B
and B to C.
2. OverlappingSubproblems:
Dynamic programming is effective when a problem can be divided into smaller
subproblems that are solved repeatedly. Unlike divide-and-conquer (e.g., mergesort), DP
reuses the results of overlapping subproblems rather than solving them independently.
Memoization vs Tabulation:
There are two approaches of the dynamic programming. The first one is the top-down approach
and the second is the bottom-up approach. Let's take a closer look at both the approaches.
Top-Down Approach
The way we solved the Fibonacci series was the top-down approach. We just start by
solving the problem in a natural manner and stored the solutions of the subproblems along the
way. We also use the term memoization, a word derived from memo for this.
In other terms, it can also be said that we just hit the problem in a natural manner and hope that
the solutions for the subproblem are already calculated and if they are not calculated, then we
calculate them on the way.
Java Program for Fibonacci (Top Down Approach) :
class Fib
{
static int[] F = new int[50]; //array to store fibonacci terms
{
F[i] = -1;
}
}
public static int dynamicFibonacci(int n)
{
if (n==0)
{
F[n] = 0;
}
else if (n == 1)
{
F[n] = 1;
}
else {
F[n] = dynamicFibonacci(n-1) + dynamicFibonacci(n-2);
}
}
return F[n];
}
Bottom-Up Approach
The other way we could have solved the Fibonacci problem was by starting from the
bottom i.e., start by calculating the 2nd2nd term and then 3rd3rd and so on and finally
calculating the higher terms on the top of these i.e., by using these values.
We use a term tabulation for this process because it is like filling up a table from the start.
class Fib
{
static int[] F = new int[50]; //array to store fibonacci terms
Note that in the matrix-chain multiplication problem, we are not actually multiplying
matrices. Our goal is only to determine an order for multiplying matrices that has the
lowest cost.
That is here is minimum cost is 5000 for above example.
So problem is we can perform a many time of cost multiplication and repeatedly the
calculation is performing. So this general method is very time consuming and tedious.
So we can apply Dynamic programming for solve this kind of problem.
The idea is to solve this problem by computing the minimum number of scalar multiplications
required for each subproblem and using the results to construct the solution to the larger
problem.
Here, k represents the position where the sequence is split for optimal multiplication.
3. Base Case:
m[i][i]= 0, because multiplying a single matrix requires no operations.
4. Tabulation:
Use a bottom-up approach to fill a 2D table, where m[i][j] is computed using
previously calculated subproblem solutions.
Algorithm in Pseudocode:
For i = 1 to n:
m[i][i] = 0 // Cost of multiplying one matrix is zero
all i.
Let us proceed with working away from the diagonal. We compute the optimal solution for the
product of 2 matrices.
consideration.
2. m (2, 3) = m2 x m3
= 10 x 3 x 3 x 12
= 10 x 3 x 12 = 360
3. m (3, 4) = m3 x m4
= 3 x 12 x 12 x 20
= 3 x 12 x 20 = 720
4. m (4,5) = m4 x m5
= 12 x 20 x 20 x 7
= 12 x 20 x 7 = 1680
We initialize the diagonal element with equal i,j value with ‘0’.
After that second diagonal is sorted out and we get all the values corresponded to it
Now the third diagonal will be solved out in the same way.
M [1, 3] = M1 M2 M3
1. There are two cases by which we can solve this multiplication:
(M1 x M2) + M3, M1+ (M2x M3)
2. After solving both cases we choose the case in which minimum output is there.
M [1, 3] =264
As Comparing both output 264 is minimum in both cases so we insert 264 in table and
M [2, 4] = M2 M3 M4
1. There are two cases by which we can solve this multiplication:
(M2x M3)+M4, M2+(M3 x M4)
2. After solving both cases we choose the case in which minimum output is there.
M [2, 4] = 1320
As Comparing both output 1320 is minimum in both cases so we insert 1320 in table and
M [3, 5] = M3 M4 M5
1. There are two cases by which we can solve this multiplication:
(M3 x M4) + M5, M3+ ( M4xM5)
2. After solving both cases we choose the case in which minimum output is there.
M [3, 5] = 1140
As Comparing both output 1140 is minimum in both cases so we insert 1140 in table and ( M3 x
After solving these cases we choose the case in which minimum output is there
M [1, 4] =1080
As comparing the output of different cases then ‘1080’ is minimum output, so we insert 1080 in
the table and (M1 xM2) x (M3 x M4) combination is taken out in output making,
M [2, 5] = M2 M3 M4 M5
After solving these cases we choose the case in which minimum output is there
M [2, 5] = 1350
As comparing the output of different cases then ‘1350’ is minimum output, so we insert 1350 in
M [1, 5] = M1 M2 M3 M4 M5
After solving these cases we choose the case in which minimum output is there
M [1, 5] = 1344
As comparing the output of different cases then ‘1344’ is minimum output, so we insert 1344 in
class ChainMatrixMul
{
public static int matrixChainMultiplication(int[] dims, int i, int j, int[][] lookup)
{
// base case: one matrix
if (j <= i + 1)
{
return 0;
}
int min = Integer.MAX_VALUE;
// if the subproblem is seen for the first time, solve it and store its result in a lookup table
if (lookup[i][j] == 0)
{
for (int k = i + 1; k <= j - 1; k++)
{
// recur for `M[i+1]…M[k]` to get an `i × k` matrix
int cost = matrixChainMultiplication(dims, i, k, lookup);
Output:
The time complexity of the above top-down solution is O(n3) and requires O(n2) extra space,
where n is the total number of matrices.
ChainMatrixMul.java
class ChainMatrixMul
{
public static int matrixChainMultiplication(int[] dims)
{
int n = dims.length;
Optimal Binary Search Tree extends the concept of Binary search tree.
Binary Search Tree (BST) is a nonlinear data structure which is used in many scientific
applications for reducing the search time.
In BST, left child is smaller than root and right child is greater than root. This arrangement
simplifies the search procedure.
Optimal Binary Search Tree (OBST) is very useful in dictionary search.
The probability of searching is different for different words. OBST has great application in
translation.
A Binary Search Tree (BST) is a tree where the key values are stored in the internal nodes.
The external nodes are null nodes.
The keys are ordered lexicographically, i.e. for each internal node all the keys in the left sub-
tree are less than the keys in the node, and all the keys in the right sub-tree are greater.
When we know the frequency of searching each one of the keys, it is quite easy to compute
the expected cost of accessing each node in the tree.
An optimal binary search tree is a BST, which has minimal expected cost of locating each
node.
Search time of an element in a BST is O(n), whereas in a Balanced-BST search time
is O(log n).
Again the search time can be improved in Optimal Cost Binary Search Tree, placing the most
frequently used data in the root and closer to the root element, while placing the least frequently
used data near leaves and in leaves.
Given a fixed set of identifiers, we wish to create a binary search tree organization.
We may expect different binary search trees for the same identifier set to have different
performance characteristics.
The tree of Figure(a) in, the worst case, requires four comparisons to find an identifier, where
as the tree of Figure(b) requires only three.
On the average the two trees need 12/5 and 11/5 comparisons respectively.
For example in the case of tree(a), it takes 1,2,2,3 and 4 comparisons, respectively,
to find the identifiers for, do, while, int & if.
Thus the average number of comparisons is (1+2+2+3+4)/5=12/5.
This calculation assumes that Each identifier is searched for with equal probability and that no
unsuccessful searches(i.e.searches for identifiers not in the tree) are made.
In a general situation, we can expect different identifiers to be searched for with different
frequencies (or probabilities).
In addition, we can expect unsuccessful searches also to be made.
Let us assume that the given set of identifiers is {a1,a2,……,an} with a1 < a2 < ……< an.
Let p(i) be the probability with which we search for ai.
Let q(i) be the probability that the identifier ‘x’ being searched for is such that ai< x < ai+1,
where 0 ≤ i ≤ n.
Then, Ʃ0 ≤ i ≤ n q(i) the probability of an unsuccessful search.
Clearly,
Ʃ0 ≤ i ≤ n p(i)+ Ʃ0 ≤ i ≤ n q(i) =1.
Given this data, we wish to construct an optimal binary search tree for {a1,a2,….. an,}.
In obtaining a cost function for binary search trees, it is useful to add a ‘’fictitious’’ node in
place of every empty sub tree in the search tree. Such nodes, called “External nodes”. All other
nodes are internal nodes.
In Fig. Square boxes indicates External Nodes.
If a binary search tree represents n identifiers, then there will be exactly ‘n’ internal
nodes and n+1 (fictitious) external nodes.
Every internal node represents a point where a successful search may terminate.
Every external node represents a point where an unsuccessful search may terminate.
The expected cost contribution from the internal node for ai is
p(i) * level(a i ).
The expected cost contribution from the External node for Ei is
q(i) * level((E i ) -1).
The preceding discussion leads to the following formula for the expected Cost of a binary
search tree
With p(1)= 0.5,p(2) = 0.1,p(3) = 0.05, q(0)= 0.15, q(1) =0.1,q(2)= 0.05 and q(3)=0.05
For instance ,cost (tree a) can be computed as follows. The contribution from successful
searches(internal nodes) is
=3 * 0.5+2*0.1+1*0.05
=1.75.
the contribution from unsuccessful searches(external nodes) is
=3 * 0.15+3 * 0.1+2 * 0.05+1*0.05
= 0.90.
Cost (tree ‘a’)=1.75+0.90=2.65.
All the other costs can also be calculated in a similar manner
Cost (tree ‘a’)=1.75+0.90=2.65.
Cost (tree ‘b’)=1.9
Cost (tree ‘c’)=1.5.
Cost (tree ‘d’)=2.05.
Cost (tree ‘e’)=1.6.
Tree ‘c’ is optimal with this assignment of p's and q's.
Above Equation can be solved for c(0,n) by first computing all c(i, j)such that j-i = 1.
Next we can compute all c(i, j) such that j-i =2, then all c(i, j) with j-i = 3, and so on.
If during this computation we record the root r(i,j) of each tree tij, then an optimal binary
search tree can be constructed from these r(i, j).
Example: Let n = 4 and (a1,a2,a3,a4)=(do, if, int, while). Let p(1:4) = (3,3,1,1) and
q(0:4) = (2,3,1,1,1)
we have w(i, i)= q(i) and c(i, i)=0 and r(i, i)= 0,
0 ≤i ≤ 4. Using above equation and the observation w(i, j)=P(j)+q(j)+w(i,j-1),we get Sol:
Compute Weight (W), Cost (C), Root (R) for j-i=1, j-i=2, j-i=3 & j-i=4
p1=3,p2=3,p3=1 & p4=1 q0=2,q1=3,q2=1,q3=1 & q4=1
for k=1&2 ,Find C(0,2),w(0,2) and R(0,2) & Take Minimum Cost and Root Value
for k=2&3, Find C(1,3),w(1,3) and R(1,3) & Take Minimum Cost and Root Value
for k=3&4, Find C(2,4),w(2,4) and R(2,4) & Take Minimum Cost and Root Value
For |j-i|=3
for k=1,2&3 ,Find C(0,3),w(0,3) and R(0,3) & Take Minimum Cost and Root Value
for k=2,3&4 ,Find C(1,4),w(1,4) and R(1,4) & Take Minimum Cost and Root Value
For |j-i|=4
for k=1,2,3 & 4,Find C(0,4),w(0,4) and R(0,4) & Take Minimum Cost ,this is
total cost of BST and Minimum K Value i.e Root , this is root node for BST.
Let G = (V, E) be a Directed graph with n vertices. Let cost be a cost Adjacency matrix
for G such that cost(i , i)=0, 1≤ i ≤n.
Then cost(i, j) is the length (or cost) of edge (i, j) if (i, j) Є E(G).
And cost(i, j)= ∞ and if i≠ j and (i,j) ∉ E(G).
The all-pairs shortest-path problem is to determine .a matrix ‘A’ such that A(i, j)is the
length of a shortest path from i to j.
The matrix ‘A’ can be obtained by solving n single-source problems using the algorithm
Shortest Paths.Since each application of this procedure requires 0(n2) time.
The matrix ‘A’ can be obtained in 0(n3)time.
We obtain an alternate 0(n3) solution to this problem using the principle of optimality.
Let us examine a shortest i to j path in G, i≠ j This path originates at vertex i and goes
through some intermediate vertices (possibly none) and terminates at vertex j.
We can assume that this path contains no cycles for if there is a cycle, then this can be
deleted without increasing the path length(no cycle has negative length)
If ‘k’ is an intermediate vertex on this Shortest path, then the sub paths from i to k and
from k to j must be shortest paths from i to k and k to j, respectively.
Otherwise, the i to j path is not of minimum length. So, the principle of optimality holds.
This alerts us to the prospect of using dynamic programming.
If ‘k’ is the intermediate vertex with highest index, then the i to k path is a shortest i to k
path in G going through no vertex with index greater than k -1.
Similarly the k to j path is a shortest k to j path in G going through no vertex of index
greater than k-1.
We can regard the construction of a shortest i to j path as first requiring a decision as
to which is the highest indexed intermediate vertex k.
Once this decision has been made, we need to find two shortest paths,
One from i to k and the other from k to j.
Neither of these may go through a Vertex with index greater than k -1.
Using Ak (i, j) to represent the length of a shortest path from i to j going through no
vertex of index greater than k, we obtain
If it does not, then no intermediate vertex has index greater than k-1.
- Hence Ak(i, j) = Ak-1(i, j)
Combining
Pseudo code:
Solution:
Optimal substructure formula for Floyd’s algorithm,
Iteration 1 : k = 1 :
D1[1, 2] = min { Do [1, 2], Do [1, 1] + Do [1, 2] }
= min {∞, 0 + ∞} = ∞
Iteration 2 (k = 2) :
D2[1, 2] = D1 [1, 2] = ∞
Iteration 3 (k = 3) :
D3[3, 1] = D2 [3, 1] = 9
D3[3, 2] = D2 [3, 2] = 7
D3[3, 4] = D2 [3, 4] = 1
Iteration 4 (k = 4) :
D4[1, 2] = min { D3 [1, 2], D3 [1, 4] + D3 [4, 2] }
= min {10, 4 + 16} = 10
D4[1, 3] = min { D3 [1, 3], D3 [1, 4] + D3 [4, 1] }
= min {3, 4 + 9} = 3
D4[1, 4] = D3 [1, 4] = 4
D4[2, 1] = min { D3 [2, 1], D3 [2, 4] + D3 [4, 1] }
= min {2, 6 + 6} = 2
D4[4, 1] = D3 [4, 1] = 6
D4[4, 2] = D3 [4, 2] = 16
D4[4, 3] = D3 [4, 3] = 9
import java.util.ArrayList;
import java.util.List;
class AllPiarsShortestpath
{
// Recursive function to print path of given vertex `u` from source vertex `v`
private static void printPath(int[][] path, int v, int u, List<Integer> route)
{
if (path[v][u] == v)
{
return;
}
printPath(path, v, path[v][u], route);
route.add(path[v][u]);
}
if (v == u) {
path[v][u] = 0;
}
else if (cost[v][u] != Integer.MAX_VALUE) {
path[v][u] = v;
}
else {
path[v][u] = -1;
}
}
}
// run Floyd–Warshall
for (int k = 0; k < n; k++)
{
for (int v = 0; v < n; v++)
{
if (cost[v][k] != Integer.MAX_VALUE
&& cost[k][u] != Integer.MAX_VALUE
&& (cost[v][k] + cost[k][u] < cost[v][u]))
{
cost[v][u] = cost[v][k] + cost[k][u];
path[v][u] = path[k][u];
}
}
Problem Statement:
A traveler needs to visit all the cities from a list, where distances between all the cities are
known and each city should be visited just once. What is the shortest possible route that he visits
each city exactly once and returns to the origin city?
Travelling salesman problem is the most notorious computational problem.
We can use brute-force approach to evaluate every possible tour and select the best one.
For n number of vertices in a graph, there are (n - 1)! number of possibilities.
Instead of brute-force using dynamic programming approach, the solution can be obtained in
lesser time, though there is no polynomial time algorithm.
Let G = (V,E) be a directed graph with edge costs Cij.
The variable Cij is defined such that
Cij > 0 for all i and j and Cij = ∞ if (i, j) ∉ E.
Let |V| = n and assume n > 1.
A tour of G is a directed simple cycle that includes every vertex in V.
The cost of a tour is “the sum of the cost of the edges on the tour”.
The traveling sales person problem is to find a tour of minimum cost.
The traveling sales person problem finds application in a variety of situations.
Example 1:
Suppose we have to route a postal van to pick up mail from mail boxes located at ‘n’ different
sites.
An ‘n + 1’ vertex graph can be used to represent the situation.
One vertex represents the post office from which the Postal van starts and to which it must
return.
Edge(i, j)is assigned a cost equal to the distance from site ‘i’ to site ‘j’.
The route taken by the postal van is a tour, and we are interested in finding a tour of minimum
length.
Example2:
suppose we wish to use a robot arm to tighten
the nuts on some piece of machinery on an assembly line.
The arm will start from its initial position (which is over the first nut to be tightened),
successively move to each of the remaining nuts, and return to the initial position.
The path of the arm is clearly a tour on a graph in which vertices represent the nuts.
A minimum-cost tour will minimize the time needed for the arm to complete its task (note
that only the total arm movement time is variable; the nut tightening time is independent of the
tour).
Example 3:
From a production environment in which several
Commodities are manufactured on the same set of machines.
The manufacture proceeds in cycles. In each production cycle, ‘n’ different commodities are
produced.
When the machines are changed from production of commodity ‘i’ to commodity ‘j’, a
change over cost Cij is incurred.
It is desired to find a sequence in which to manufacture these commodities.
This sequence should minimize the sum of changeover costs(the remaining production costs
are sequence independent).
Since the manufacture proceeds cyclically, It is necessary to include the cost of starting the
next cycle.
-This is just the change over cost from the last to the first commodity.
-Hence, this problem can be regarded as a traveling sales person problem on an ‘n’ vertex
graph with edge
cost Cij's being the change over cost from commodity ‘i’ to commodity ’j’.
In the following discussion we shall, without loss of generality, regard a tour to be a simple
path that starts and ends at vertex ‘1’.
Every tour consists of an edge (i, k) for some k ∈V-{1}. and a path from vertex ‘k’ to vertex
‘1’.
The path from vertex ‘k’ to vertex ‘1’ goes through each vertex in V-{1,k} exactly once.
It is easy to see that if the tour is optimal, then the path from ‘k’ to ‘1’ must be a shortest ‘k’
to ‘1’ path going through all vertices in V-{1,k} .
Hence, the principle of optimality holds.
Let g(i, S) be the length of a shortest path starting at vertex ‘i’ ,going through all vertices in
‘S’, and terminating at vertex ‘1’.
The function g(1 ,V-{1}) is the length of an optimal sales person tour.
From the principal of optimality it follows that
1st Equation can be solved for g(1,V-{1}) if we know g(k, V -{1, k}) for all choices of
‘k’.
The ‘g’ values can be obtained by using Eq.2
Clearly ,
Given a set of items, each having different weight and value or profit associated with it.
Find the set of items such that the total weight is less than or equal to a capacity of the
knapsack and the total value earned is as large as possible.
The knapsack problem is useful in solving resource allocation problem.
Let X = < x1, x2, x3, . . . . . , xn> be the set of n items. Sets W = <w1, w2, w3, . . . , wn> and
V = < v1, v2, v3, . . . , vn> are weight and value associated with each item in X.
Knapsack capacity is M unit.
The knapsack problem is to find the set of items which maximizes the profit such that
collective weight of selected items does not cross the knapsack capacity.
Select items from X and fill the knapsack such that it would maximize the profit.
Knapsack problem has two variations. 0/1 knapsack, that does not allow breaking of
items. Either add an entire item or reject it. It is also known as a binary knapsack.
Fractional knapsack allows breaking of items. Profit will be earned proportionally.
Mathematical formulation
We can select any item only ones. We can put items x i in knapsack if knapsack can
accommodate it. If the item is added to a knapsack, the associated profit is accumulated.
Step-3: fn(M) = Sn. This will find the solution of KNAPSACK(1, n, M).
Purging Rule:
Step-4: for each pair (p, w) ∈ Sn
if (p, w) ∈ Sn , &
if (p, w) ∉ Sn – 1, then set xn = 1 otherwiae xn = 0 and
update p = p – xn and w = w – wn
Example-1: Solve the instance of 0/1 knapsack problem using dynamic Programming :
n = 4, M = 25, (P1, P2, P3 P4) = (10, 12, 14, 16), (W1, W2, W3, W4) = (9, 8, 12, 14)
Solution:
Knapsack capacity is very large, i.e. 25, so tabular approach won’t be suitable. We will use the
set method to solve this problem
Initially, S0 = { (0, 0) }
Iteration 1:
Obtain S10 by adding pair (p1, w1) = (10, 9) to each pair of S0
S10 = S0 + (10, 9) = {(10, 9)}
Obtain S1 by merging and purging S0 and S10
S1 = MERGE_PURGE (S0, S10)
= { (0, 0), (10, 9) }
Iteration 2:
Iteration 3:
Obtain S12 by adding pair (p3, w3) = (14, 12) to each pair of S2
S12 = S2 + (14, 12)
= { (14, 12), (26, 20), (36, 29) }
Iteration 4:
Obtain S13 by adding pair (p4, w4) = (16, 14) to each pair of S3
S13 = S3 + (16, 14)
= { (16, 14), (28, 22), (38, 31), (30, 26), (42, 34) }
Pair (38, 31), (30, 26) ,and (42, 34) are discarded because its w > M
So set xn = x4 = 1
Update,
p = p – p4 = 28 – 16 = 12
w = w – w4 = 22 – 14 = 8
n=n–1=4–1=3
p = p – p2 = 12 – 12 = 0
w = w – w2 = 8 – 8 = 0
Problem size is 0, so stop.
Optimal solution vector is (x1, x2, x3, x3) = (0, 1, 0, 1) Thus, this approach selects pair (12, 8)
and (16, 14) which gives profit of 28.
Iteration 2:
Obtain S11 by adding pair (p2, w2) = (2, 3) to each pair of S1
S11 = S1 + (2, 3) = {(2, 3), (3, 5)}
Obtain S2 by merging and purging S1 and S11
S2 = MERGE_PURGE(S1, S11)
= { (0, 0), (1, 2), (2, 3), (3, 5) }
Iteration 3:
Obtain S12 by adding pair (p3, w3) = (5, 4) to each pair of S2
S12 = S2 + (5, 4) = {(5, 4), (6, 6), (7, 7), (8, 9) }
Obtain S3 by merging and purging S2 and S12 .
S3 = MERGE_PURGE (S2, S12)
= { (0, 0), (1, 2), (2, 3), (5, 4), (6, 6) }
p = p – p3 = 6 – 5 = 1
w = w – w3 = 6 – 4 = 2
Now n = 2, pair(1, 2) ∈ S2 and (1, 2) ∈ S1
So set xn = x2 = 0
Now n = 1, pair(1, 2) ∈ S1 but (1, 2) ∉ S0
So set xn = x1 = 1
Optimal solution vector is (x1, x2, x3) = (1, 0, 1) Thus, this approach selects pair (1, 2)
and (5, 4).
If the weight of the item is larger than the remaining knapsack capacity, we skip the item, and
the solution of the previous step remains as it is. Otherwise, we should add the item to the
solution set and the problem size will be reduced by the weight of that item. Corresponding
profit will be added for the selected item.
Dynamic programming divides the problem into small sub-problems. Let V is an array of the
solution of sub-problems. V[i, j] represents the solution for problem size j with first i items. The
mathematical notion of the knapsack problem is given as :
Example: Find an optimal solution for following 0/1 Knapsack problem using dynamic
programming: Number of objects n = 4, Knapsack Capacity M = 5, Weights (W1, W2, W3, W4) =
(2, 3, 4, 5) and profits (P1, P2, P3, P4) = (3, 4, 5, 6).
Solution:
Solution of the knapsack problem is defined as,
I1 2 3
I2 3 4
I3 4 5
I4 5 6
Item Detail 0 1 2 3 4 5
i=0 0 0 0 0 0 0
V [2, 1] ⇒ i = 2, j = 1, wi = w2 = 3
As, j < wi, V [i, j] = V [i – 1, j]
V [2, 1] = V [1, 1] = 0
V [3, 1] ⇒ i = 3, j = 1, wi = w3 = 4
As, j < wi, V [i, j] = V [i – 1, j]
V [3, 1] = V [2, 1] = 0
V [4, 1] ⇒ i = 4, j = 1, wi = w4 = 5
As, j < wi, V[i, j] = V[i – 1, j]
V [4, 1] = V [3, 1] = 0
V[2, 2] ⇒ i = 2, j = 2, wi = w2 = 3, vi = 4
As, j < wi, V [i, j] = V[i – 1, j]
V[2, 2] = V[1, 2] = 3
V[3, 2] ⇒ i = 3, j = 2, wi = w3 = 4, vi = 5
As, j < wi, V[i, j] = V[i – 1, j]
V[3, 2] = V [2, 2] = 3
V[4, 2] ⇒ i = 4, j = 2, wi = w4 = 5, vi = 6
As, j < wi, V[i, j] = V[i – 1, j]
V[4, 2] = V[3, 2] = 3
V[2, 3] ⇒ i = 2, j = 3, wi = w2 = 3, vi = 4
As, j ≥ wi, V [i, j] = max {V [i – 1, j], vi + V [i – 1, j – wi] }
= max {V [1, 3], 4 + V [1, 0]}
V[3, 3] ⇒ i = 3, j = 3, wi = w3 = 4, vi = 5
As, j < wi, V [i, j] = V [i – 1, j]
V[3, 3] = V [2, 3] = 4
V[4, 3] ⇒ i = 4, j = 3, wi = w4 = 5, vi = 6
As, j < wi, V[i, j] = V[i – 1, j]
V[4, 3] = V [3, 3] = 4
V[2, 4] ⇒ i = 2, j = 4, wi = w2 = 3 , vi = 4
As, j ≥ wi, V [i, j] =max {V [i – 1, j], vi + V [i – 1, j – wi] }
= max {V [1, 4], 4 + V [1, 1]}
V[3, 4] ⇒ i = 3, j = 4, wi = w3 = 4, vi = 5
As, j ≥ wi, V [i, j]=max {V [i – 1, j], vi + V [i – 1, j – wi] }
= max {V [2, 4], 5 + V [2, 0]}
V[4, 4] ⇒ i = 4, j = 4, wi = w4 = 5, vi = 6
As, j < wi, V [i, j] = V [i – 1, j]
V[4, 4] = V [3, 4] = 5
V[2, 5] ⇒ i = 2, j = 5, wi = w2 = 3, vi = 4
As, j ≥ wi, V [i, j] =max {V [i – 1, j], vi + V [i – 1, j – wi] }
= max {V [1, 5], 4 + V [1, 2]}
V[3, 5] ⇒ i = 3, j = 5, wi = w3 = 4, vi = 5
As, j ≥ wi, V [i, j] = max {V [i – 1, j], vi + V [i – 1, j – wi] }
V [4, 5] ⇒ i = 4, j = 5, wi = w4 =5, vi = 6
As, j ≥ wi, V [i, j] = max {V [i – 1, j], vi + V [i – 1, j – wi] }
= max {V [3, 5], 6 + V [3, 0]}
j→
Item Detail 0 1 2 3 4 5
i=0 0 0 0 0 0 0
Complexity analysis
With n items, there exist 2n subsets, the brute force approach examines all subsets to find
the optimal solution. Hence, the running time of the brute force approach is O(2n). This is
unacceptable for large n.
Dynamic programming finds an optimal solution by constructing a table of size n ´ M, where n is
a number of items and M is the capacity of the knapsack. This table can be filled up in O(nM)
time, same is the space complexity.
6. Climbing Stairs:
Given a staircase of N steps and you can either climb 1 or 2 steps at a given time. The task is to
return the count of distinct ways to climb to the top.
Note: The order of the steps taken matters.
Examples:
Input: N = 3
Output: 3
Explanation:
There are three distinct ways of climbing a staircase of 3 steps :
[1, 1, 1], [2, 1] and [1, 2].
Input: N=2 = 2
Output: 2
Explanation:
There are two distinct ways of climbing a staircase of 2 steps :
[1, 1] and [2].
Input: n = 4
Output: 5
(1, 1, 1, 1), (1, 1, 2), (2, 1, 1), (1, 2, 1), (2, 2)
import java.util.*;
class ClimbingStairs
{
public int climbStairs(int n)
{
if (n == 1) {
return 1;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
System.out.println(new ClimbingStairs().climbStairs(n));
}
}
Sample i/p & o/p:
Case=1
input =9
output =55
Case =2
input =2
output =2
Case =3
input =20
output =10946
Java Program for Climbing Stairs Using Dynamic Programming (Top-Down Approach):
ClimbingStairs.java
import java.util.*;
class ClimbingStairs
{
if (n < 0)
{
return 0;
}
else if (memo[n] != 0)
{
// If we stored something in our cache reuse it and avoid recalculating everything
return memo[n];
}
else if (n == 0)
{
return 1;
}
else
{
// store our calculation inside our cache so we don't have to recalculate it again for //memo[n]
memo[n] = climbStairs(n-1) + climbStairs(n-2);
return memo[n];
}
}
You are given an integer array cost where cost[i] is the cost of i step on a staircase.
Once you pay the cost, you can either climb one or two steps.
You can either start from the step with index 0 , or the step with index 1 .
Return the minimum cost to reach the top of the floor.
Example 1:
Input: cost = [10,15,20]
Output: 15
Example 2:
Input: cost = [1,100,1,1,1,100,1,1,100,1]
Output: 6
Explanation: You will start at index 0.
- Pay 1 and climb two steps to reach index 2.
- Pay 1 and climb two steps to reach index 4.
- Pay 1 and climb two steps to reach index 6.
- Pay 1 and climb one step to reach index 7.
- Pay 1 and climb two steps to reach index 9.
- Pay 1 and climb one step to reach the top.
The total cost is 6.
Approach:
At each step, we can consider the answer to be the combined cost of the current step, plus the
lesser result of the total cost of each of the solutions starting at the next two steps.
This means that, thinking backwards, we can solve for the smallest problem first, and then
build down from there.
For the last two steps, the answer is clearly their individual cost. For the third to last step, it's
that step's cost, plus the lower of the last two steps.
Now that we know that, we can store that data for later use at lower steps. Normally, this
would call for a DP array, but in this case, we could simply store the values in-place.
(Note: If we choose to not modify the input, we could create a DP array to store this
information at the expense of O(N) extra space.)
So we should iterate downward from the end, starting at the third step from the end, and
update the values in cost[i] with the best total cost from cost[i] to the end.
Then, once we reach the bottom of the steps, we can choose the best result
of cost[0] and cost[1] and return our answer.
Java Program For Minimum Cost Climbing Stairs Using Dynamic Programming
MinCostClimbingStairs.java
import java.util.*;
class MinCostClimbingStairs
{
public int minCostClimbingStairs(int[] cost)
{
int n = cost.length;
int[] dp = new int[n];
for (int i=0; i<n; i++) {
if (i<2) dp[i] = cost[i];
else dp[i] = cost[i] + Math.min(dp[i-1], dp[i-2]);
}
return Math.min(dp[n-1], dp[n-2]);
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int ar[]=new int[n];
for(int i=0;i<n;i++)
ar[i]=sc.nextInt();
System.out.println(new MinCostClimbingStairs().minCostClimbingStairs(ar));
}
}
Sample i/p & o/p:
case =1
input =3
20 30 40
output =30
case =2
input =7
2 3 50 2 2 50 2
output =9
Example 1:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Example 2:
Input: nums = [1]
Output: 1
Example 3:
Input: nums = [5,4,-1,7,8]
Output: 23
Define two-variable currSum which stores maximum sum ending here and maxSum
which stores maximum sum so far.
Initialize currSum with 0 and maxSum with INT_MIN.
Now, iterate over the array and add the value of the current element to currSum and
check
o If currSum is greater than maxSum, update maxSum equals to currSum.
o If currSum is less than zero, make currSum equal to zero.
Finally, print the value of maxSum.
Example:
class MaxSubArray
{
public int maxSubArray(int[] A)
{
int n = A.length;
int[] dp = new int[n];//dp[i] means the maximum subarray ending with A[i];
dp[0] = A[0];
int max = dp[0];
for(int i = 1; i < n; i++){
dp[i] = A[i] + (dp[i - 1] > 0 ? dp[i - 1] : 0);
max = Math.max(max, dp[i]);
}
return max;
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int ar[]=new int[n];
for(int i=0;i<n;i++)
ar[i]=sc.nextInt();
System.out.println(new MaxSubArray(). maxSubArray(ar));
}
}
Example:1
input =9
-2 1 -3 4 -1 2 1 -5 4
output =6
Example:2
input =2
1 -2
output =1
Example:3
input =20
6 -2 -7 7 -4 3 5 -5 7 -7 9 4 7 -5 -7 5 1 2 -3 3
output =26
Example 2:
Input:
grid = [[1, 1, 1],
[1, 1, 1],
[1, 1, 1]]
Output: 9
Explanation: There are four 2x2 rectangles, four 2x3 and 3x2 rectangles, and one 3x3 rectangle.
Approach:
1. Matrix Representation: The matrix is of size m x n, and we need to check for pairs of
rows that can form rectangles with 1s as corners.
2. Observations:
o A rectangle's top-left corner and bottom-left corner lie in the same column, as do
its top-right and bottom-right corners.
o For any two rows i and j, if column c1 and column c2 have 1s in both rows, they
form a rectangle.
3. Dynamic Programming Idea:
o Let dp[j] represent the count of columns where both row i and row j have a 1 up
to the current column.
o As we iterate through columns for rows i and j, count the number of rectangles
that can be formed using the pairs in dp[j].
Algorithm:
Java Program for Count Number Of Corner Rectangles Using dynamic Programming:
CountCornerRectangles.java
import java.util.*;
class CountCornerRectangles
{
public int countCornerRectangles(int[][] grid)
{
int m = grid.length, n = grid[0].length;
int[][] dp = new int[n][n];
int res = 0;
for(int i = 0;i < m;i++)
{
for(int j = 0;j < n;j++)
{
if(grid[i][j] != 1) continue;
for(int k = j+1;k < n;k++)
{
if(grid[i][k] == 1)
{
res += dp[j][k];
dp[j][k]++;
}
}
}
}
return res;
}
public static void main(String args[])
{
Scanner sc=new Scanner(System.in);
int m=sc.nextInt();
int n=sc.nextInt();
int grid[][]=new int[m][n];
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
grid[i][j]=sc.nextInt();
System.out.println(new CountCornerRectangles().countCornerRectangles(grid));
}
Example-1:
input =3 4
1010
1111
0111
output =4
Example-2:
input =4 6
101111
101101
010111
111101
output =25
Example-3:
input =5 5
11111
11111
11111
11111
11111
output =100
PART-2 Strings: Introduction, Count Substrings with Only One Distinct Letter, Valid Word
Abbreviation, Longest Repeating Substring, Longest Common Subsequence, Longest Increasing
Subsequence.
Introduction:
Strings are an incredibly common type of data in computers. This page introduces the basics of
Java strings: chars, +, length(), and substring().
A Java string is a series of characters gathered together, like the word "Hello", or the phrase
"practice makes perfect". Create a string in the code by writing its chars out between double
quotes.
String + Concatenation
Tthe + (plus) operator between strings puts them together to make a new, bigger string. The
bigger string is just the chars of the first string put together with the chars of the second string.
Strings are not just made of the letters a-z. Chars can be punctuation and other miscellelaneous
chars. For example in the string "hi ", the 3rd char is a space. This all works with strings stored
in variables too, like this:
String Length
The "length" of a string is just the number of chars in it. So "hi" is length 2 and "Hello" is length
5. The length() method on a string returns its length, like this:
String a = "Hello";
int len = a.length(); // len is 5
The chars in a string are identified by "index" numbers. In "Hello" the leftmost char (H) is at
index 0, the next char (e) is at index 1, and so on. The index of the last char is always one less
than the length. In this case the length is 5 and 'o' is at index 4. Put another way, the chars in a
string are at indexes 0, 1, 2, .. up through length-1. We'll use the index numbers to slice and dice
strings with substring() in the next section.
String Substring v1
str.substring(start)
Chars beginning at index start
Through the end of the string
Later: more complex 2-arg substring()
The substring() method picks out a part of string using index numbers to identify the desired
part. The simplest form, substring(int start) takes a start index number and returns a new string
made of the chars starting at that index and running through the end of the string:
Above str.substring(1) returns "ello", picking out the part of "Hello" which begins at index 1 (the
"H" is at index 0, the "e" is at index 1).
The java string valueOf() method converts different types of values into string. By the help
of string valueOf() method, you can convert int to string, long to string, boolean to string,
character to string, float to string, double to string, object to string and char array to string.
Internal implementation
public static String valueOf(Object obj)
{
return (obj == null) ? "null" : obj.toString();
}
Signature
Returns
Output: 3010
3010
This is a boolean version of overloaded valueOf() method. It takes boolean value and returns a
string. Let's see an example.
Output:
true
false
Applications:
Given a string s, return the number of substrings that have only one distinct letter.
Example 1:
Input: s = "aaaba"
Output: 8
Explanation: The substrings with one distinct letter are "aaa", "aa", "a", "b".
"aaa" occurs 1 time.
"aa" occurs 2 times.
"a" occurs 4 times.
"b" occurs 1 time.
So the answer is 1 + 2 + 4 + 1 = 8.
Example 2:
Input: s = "aaaaaaaaaa"
Output: 55
Approach:
1. Problem Understanding:
o You are given a string s, and you need to find all substrings where all characters
are the same.
o Example: In the string “aaa”, the valid substrings are:
"a", "a", "a", "aa", "aa", "aaa".
Total = 6.
2. Dynamic Programming Observation:
o Let dp[i] represent the number of substrings ending at index i where all characters
are the same.
o If s[i] == s[i-1], then dp[i] = dp[i-1] + 1. This is because the current character can
extend all valid substrings ending at i-1.
o If s[i] != s[i-1], then dp[i] = 1 since the substring consisting of s[i] itself is valid.
3. Final Result:
o The total number of substrings is the sum of all values in the dp array.
Time Complexity:
Java Program for Count Substrings with Only One Distinct Letter using Dynamic
Programming: CountSubstringsWithOneDistinctLetter.java
import java.util.*;
Example-1
Input:
abcde
Output:
5
Given a non-empty string s and an abbreviation abbr , return whether the string matches with
the given abbreviation.
A string such as "word" contains only the following valid abbreviations:
["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1", "1o2",
"2r1", "3d", "w3", "4"]
Notice that only the above abbreviations are valid abbreviations of the string "word" . Any other
string is not a valid abbreviation of "word”.
Note: Assume s contains only lowercase letters and abbr contains only lowercase letters and
digits.
Example 1:
Given s = "internationalization", abbr = "i12iz4n"
Return true.
Example 2:
Given s = "apple", abbr = "a2e"
Return false.
import java.util.*;
class ValidWordAbbreviation
{
public boolean validWordAbbreviation(String word, String abbr)
{
int i = 0, j = 0;
while (i < word.length() && j < abbr.length())
{
if (word.charAt(i) == abbr.charAt(j)) {
++i;++j;
continue;
}
if (abbr.charAt(j) <= '0' || abbr.charAt(j) > '9')
{
return false;
}
int start = j;
while (j < abbr.length() && abbr.charAt(j) >= '0' && abbr.charAt(j) <= '9')
{
++j;
}
int num = Integer.valueOf(abbr.substring(start, j));
i += num;
}
return i == word.length() && j == abbr.length();
}
public static void main(String args[])
{
Scanner sc=new Scanner(System.in);
String s=sc.next();
String t=sc.next();
System.out.println(new ValidWordAbbreviation().validWordAbbreviation(s,t));
}
}
Input:
internationalization
i12iz4n
Output:
true
Given a string S, find out the length of the longest repeating substring(s). Return 0 if no repeating
substring exists.
Example 1:
Input: "abcd"
Output: 0
Explanation: There is no repeating substring.
Example 2:
Input: "abbaba"
Output: 2
Explanation: The longest repeating substrings are "ab" and "ba", each of which occurs twice.
Example 3:
Input: "aabcaabdaab"
Output: 3
Explanation: The longest repeating substring is "aab", which occurs 3 times.
Example 4:
Input: "aaaaa"
Output: 4
Explanation: The longest repeating substring is "aaaa", which occurs twice.
Example: String=”AABB”
We can observe in the above table that the length of the longest repeated subsequence is 2
First, we will put '-' under the empty string as shown in the above table.
Case=1
lrs[i] is not equal to lrs[j] and i is not equal to j so lrs[i][j] would be the maximum of top and
left.
Case=2
lrs[i] is equal to lrs[j] and i is equal to j so lrs[i][j] would be the maximum of top and left.
Case=3
lrs[i] is equal to lrs[j] and 'i' is not equal to 'j' . Therefore, the lrs[i][i] would be equal to
(diagonal element + current element).
As we can observe in the above table that AB is the longest repeating subsequence. We have
basically found the LRS by using the constraint that (i==j) and s[i] == s[j] then it will not
contribute to the repeating subsequence otherwise it will contribute.
import java.util.*
class LRS
{
static int longestRepeatingSubsequence(String s)
{
int n = s.length();
int[][] dp = new int[n + 1][n + 1];
return dp[n][n];
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
String s = sc.next();
int res = longestRepeatingSubsequence(s);
System.out.println(res);
}
}
Input: abbaba
Output: 2
Given two strings text1 and text2 , return the length of their longest common subsequence.
A subsequence of a string is a new string generated from the original string with some
characters(can be none) deleted without changing the relative order of the remaining characters.
(eg, "ace" is a subsequence of "abcde" while "aec" is not). A common subsequence of two strings
is a subsequence that is common to both strings.
If there is no common subsequence, return 0.
Example 1:
Input: text1 = "abcde", text2 = "ace"
Output: 3
Explanation: The longest common subsequence is "ace" and its length is 3.
Example 2:
Input: text1 = "abc", text2 = "abc"
Output: 3
Explanation: The longest common subsequence is "abc" and its length is 3.
Example 3:
Input: text1 = "abc", text2 = "def"
Output: 0
Explanation: There is no such common subsequence, so the result is 0.
Approach:
The top-down approach memorizes results in a recursive solution, whereas the bottom-up
approach builds a solution from the base case. Hence, for this particular problem, we will
formulate a bottom-up solution.
Problem Statement: Create a program to find out the length of longest common subsequence for
strings A = “ASDGHJPL”, B = “WSFDHPLJ”.
we starts comparing characters in sequences from beginning and apply above function rules for
lcs at each comparison. The table that is constructed when program finish is:
If characters at i and j are equal then we add 1 to value present in i-1 and j-1 cell. If character at i
and j position are not equal then we pick maximum of value at i-1, j or i, j-1. After table is filled
completely we check last value in table for length of LCS.
import java.util.*;
char[] X = s1.toCharArray();
char[] Y = s2.toCharArray();
int m = X.length;
int n = Y.length;
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}.
Example-1:
Input: arr[] = {5,4,1,2,3}
Output: Length of LIS = 3
Explanation: The longest increasing subsequence is 1,2,3
Example-2:
Input: arr[] = {7,5}
Output: Length of LIS = 1
Explanation: The longest increasing subsequences are {5} or {7}.
Iteration-wise simulation:
import java.util.*;
// Build the dp array where dp[i] represents the length of the LIS ending at index i
for (int i = 1; i < n; i++)
{
for (int j = 0; j < i; j++)
{
if (nums[i] > nums[j])
{
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
// The result is the maximum value in the dp array
int maxLength = 0;
for (int i = 0; i < n; i++)
{
maxLength = Math.max(maxLength, dp[i]);
}
return maxLength;
}
for(int i=0;i<n;i++)
{
nums[i]=sc.nextInt();
}
System.out.println(new LIS().lengthOfLIS(nums));
}
}
Example-1:
Input:
5,4,1,2,3
Output:
3
Example-2:
Input:
7,5
Output:
1