Geeks DP
Geeks DP
Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 1, 2, 3, 4, 5, 6, 8, 9, 10, 12,
15, … shows the first 11 ugly numbers. By convention, 1 is included.
ugly[i] = next_ugly_no
if (next_ugly_no == next_mulitple_of_2)
{
i2 = i2 + 1;
next_mulitple_of_2 = ugly[i2]*2;
}
if (next_ugly_no == next_mulitple_of_3)
{
i3 = i3 + 1;
next_mulitple_of_3 = ugly[i3]*3;
}
if (next_ugly_no == next_mulitple_of_5)
{
i5 = i5 + 1;
next_mulitple_of_5 = ugly[i5]*5;
}
Time Complexity: O(n)
Auxiliary Space: O(n)
Let arr[0..n-1] be the input array and L(i) be the length of the LIS ending at index i such that arr[i] is the last
element of the LIS.
Then, L(i) can be recursively written as:
L(i) = 1 + max( L(j) ) where 0 < j < i and arr[j] < arr[i]; or
L(i) = 1, if no such j exists.
To find the LIS for a given array, we need to return max(L(i)) where 0 < i < n.
Note that the time complexity of the above Dynamic Programming (DP) solution is O(n^2) and there is a
O(nLogn) solution for the LIS problem.
Let us consider another sample A = {2, 5, 3}. Say, the next element is 1. How can it extend the current
sequences {2,3} or {2, 5}. Obviously, it can’t extend either. Yet, there is a potential that the new smallest
element can be start of an LIS. To make it clear, consider the array is {2, 5, 3, 1, 2, 3, 4, 5, 6}. Making 1 as
new sequence will create new sequence which is largest.
The observation is, when we encounter new smallest element in the array, it can be a potential candidate to
start new sequence.
we have maintained the condition, “end element of smaller list is smaller than end elements of larger lists“
Note that we are dealing with end elements only. We need not to maintain all the lists. We can store the end
elements in an array. Discarding operation can be simulated with replacement, and extending a list
is analogous to adding more elements to array.
To discard an element, we will trace ceil value of A[i] in auxiliary array (again observe the end elements in
your rough work), and replace ceil value with A[i]. We extend a list by adding element to auxiliary array. We
also maintain a counter to keep track of auxiliary array length.
The loop runs for N elements. In the worst case (what is worst case input?), we may end up querying ceil
value using binary search (log i) for many A[i].
Therefore, T(n) < O( log N! ) = O(N log N). Analyse to ensure that the upper and lower bounds are also O( N
log N ). The complexity is THETA (N log N).
‘Patience sorting’
tailTable[0] = A[0];
len = 1;
for (int i = 1; i < size; i++)
{
if (A[i] < tailTable[0])
// new smallest value
tailTable[0] = A[i];
else
// A[i] wants to be current end candidate of an existing
// subsequence. It will replace ceil value in tailTable
tailTable[CeilIndex(tailTable, -1, len-1, A[i])] = A[i];
}
return len;
}
Cutting a Rod
Given a rod of length n inches and an array of prices that contains 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
length of the rod is 8 and the values of different pieces are given as following, then the maximum obtainable
value is 22 (by cutting in two pieces of lengths 2 and 6)
Let cutRoad(n) be the required (best possible price) value for a rod of lenght n. cutRod(n) can be written as
following.
The given problem is also a variation of Activity Selection problem and can be solved in (nLogn) time. To
solve it as a activity selection problem, consider the first element of a pair as start time in activity selection
problem, and the second element of pair as end time.
Dynamic Programming can be used to find the longest common substring in O(m*n) time. The idea is to find
length of the longest common suffix for all substrings of both strings and store these lengths in a table.
The maximum length Longest Common Suffix is the longest common substring.
LCSubStr(X, Y, m, n) = Max(LCSuff(X, Y, i, j)) where 1 <= i <= m
and 1 <= j <= n
// return 2nCn/(n+1)
return c/(n+1);
This problem is a variation of coin change problem and can be solved in O(n) time and O(n) auxiliary space.
Tiling Problem
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.
Let “count(n)” be the count of ways to place tiles on a “2 x n” grid, we have following two ways to place first
tile.
1) If we place first tile vertically, the problem reduces to “count(n-1)”
2) If we place first tile horizontally, we have to place second tile also horizontally. So the problem reduces to
“count(n-2)”
| 1, 1 < = n < m
count(n) = | 2, n = m
| count(n-1) + count(n-m), m < n
Count even length binary sequences with same sum of first and
second half bits
Given a number n, find count of all binary sequences of length 2n such that sum of first n bits is same as sum
of last n bits.
Input: n = 2
Output: 2
There are 6 sequences of length 2*n, the
sequences are 0101, 0110, 1010, 1001, 0000
and 1111
The idea is to fix first and last bits and then recur for n-1, i.e., remaining 2(n-1) bits. There are following
possibilities when we fix first and last bits.
1) First and last bits are same, remaining n-1 bits on both sides should also have the same sum.
2) First bit is 1 and last bit is 0, sum of remaining n-1 bits on left side should be 1 less than the sum n-1 bits
on right side.
2) First bit is 0 and last bit is 1, sum of remaining n-1 bits on left side should be 1 more than the sum n-1 bits
on right side.
diff is the expected difference between sum of first half digits and last half digits. Initially diff is 0.
No. of 2*n bit strings such that first n bits have 0 ones &
last n bits have 0 ones = nC0 * nC0
No. of 2*n bit strings such that first n bits have 1 ones &
last n bits have 1 ones = nC1 * nC1
....
and so on.
int countSeq(int n)
{
int nCr=1, res = 1;
res += nCr*nCr;
}
return res;
}
return dp[rhs];
}
Input: n = 2
Output: Number of ways = 2
Explanation: Let the set be {1, 2}
{ {1}, {2} }
{ {1, 2} }
Compute nCr % p
Working of Above formula and Pascal Triangle:
Let us see how above formula works for C(4,3)
1==========>> n = 0, C(0,0) = 1
1–1========>> n = 1, C(1,0) = 1, C(1,1) = 1
1–2–1======>> n = 2, C(2,0) = 1, C(2,1) = 2, C(2,2) = 1
1–3–3–1====>> n = 3, C(3,0) = 1, C(3,1) = 3, C(3,2) = 3, C(3,3)=1
1–4–6–4–1==>> n = 4, C(4,0) = 1, C(4,1) = 4, C(4,2) = 6, C(4,3)=4, C(4,4)=1
Time Complexity: Time complexity of this solution is O(p2 * Logp n). There are O(Logp n) digits in base p
representation of n. Each of these digits is smaller than p, therefore, computations for individual digits take
O(p2). Note that these computations are done using DP method which takes O(n*r) time.
Permutation Coefficient
Permutation refers to the process of arranging all the members of a given set to form a sequence. The
number of permutations on a set of n elements is given by n! , where “!” represents factorial.
The Permutation Coefficient represented by P(n, k) is used to represent the number of ways to obtain an
ordered subset having k elements from a set of n elements.
if (i == 0 || j == 0)
L[i][j] = 0;
else
L[i][j] = max(L[i-1][j], L[i][j-1]);
One important observation in above simple implementation is, in each iteration of outer loop we only,
need values from all columns of previous row. So there is no need of storing all rows in our DP matrix, we
can just store two rows at a time and use them, in that way used space will reduce from L[m+1][n+1] to L[2]
[n+1]. Below is C++ implementation of this idea.
int lcs(string &X, string &Y)
{
// Find lengths of two strings
int m = X.length(), n = Y.length();
int L[2][n+1];
// Binary index, used to index current row and
// previous row.
bool bi;
else
L[bi][j] = max(L[1-bi][j], L[bi][j-1]);
}
}
A snake sequence is made up of adjacent numbers in the grid such that for each number, the number on the
right or the number below it is +1 or -1 its value. For example, if you are at location (x, y) in the grid, you can
either move right i.e. (x, y+1) if that number is ± 1 or move down i.e. (x+1, y) if that number is ± 1.
Let T[i][i] represent maximum length of a snake which ends at cell (i, j), then for given matrix M, the DP
relation is defined as –
T[0][0] = 0
T[i][j] = max(T[i][j], T[i][j – 1] + 1) if M[i][j] = M[i][j – 1] ± 1
T[i][j] = max(T[i][j], T[i – 1][j] + 1) if M[i][j] = M[i – 1][j] ± 1
Time complexity of above solution is O(M*N). Auxiliary space used by above solution is O(M*N). If we are not
required to print the snake, space can be further reduced to O(N) as we only uses the result from last row.
Find the minimum total cost to buy exactly W kg oranges and if it is not possible to buy exactly W kg oranges
then print -1. It may be assumed that there is infinite supply of all available packet types.
This problem is can be reduced to 0-1 Knapsack Problem. So in cost array, we first ignore those packets
which are not available i.e; cost is -1 and then traverse the cost array and create two array val[] for storing
cost of ‘i’ kg packet of orange and wt[] for storing weight of corresponding packet. Suppose cost[i] = 50 so
weight of packet will be i and cost will be 50.
If i == 0 and j == 0
maxCost(0, 0) = mat[0][0]
return dp[n];
dp[i] = dp[i-1];
return maxSum;
}
sum[0] = arr[0]
In general,
// We have three cases
// 1) Exclude arr[i], i.e., sum[i] = sum[i-1]
// 2) Exclude arr[i-1], i.e., sum[i] = sum[i-2] + arr[i]
// 3) Exclude arr[i-2], i.e., sum[i-3] + arr[i] + arr[i-1]
sum[i] = max(sum[i-1], sum[i-2] + arr[i],
sum[i-3] + arr[i] + arr[i-1])
This problem is based upon the concept of Longest Increasing Subsequence Problem.
Time Complexity: O(n*sqrt(n)).
Maximum sum Bi-tonic Sub-sequence
Given an array of integers. A subsequence of arr[] is called Bitonic if it is first increasing, then decreasing.
Let the input sequences be X[0..m-1], Y[0..n-1] and Z[0..o-1] of lengths m, n and o respectively. And let
L(X[0..m-1], Y[0..n-1], Z[0..o-1]) be the lengths of LCS of the three sequences X, Y and Z. Following is the
implementation:
while ( n > 1)
{
if (n % 3 == 0)
n /= 3;
else if (n % 2 == 0)
n /= 2;
else
n--;
steps++;
}
If we observe carefully, the greedy strategy doesn’t work here.
Eg: Given n = 10 , Greedy –> 10 /2 = 5 -1 = 4 /2 = 2 /2 = 1 ( 4 steps ).
But the optimal way is –> 10 -1 = 9 /3 = 3 /3 = 1 ( 3 steps ).
So, we must think of dynamic approach for optimal solution.
Dynamic Approach:
For finding minimum steps we have three possibilities for n and they are:
f(n) = 1 + f(n-1)
f(n) = 1 + f(n/2) // if n is divisible by 2
f(n) = 1 + f(n/3) // if n is divisible by 3
We can easily say that if there is a zero at any position, then it will block path for all the positions left to it and
top of it.Also, we can say that any position (i,j) will have an endless row if (i,j+1) will have an endless row and
value of (i,j) is 1.
Similarly, we can say that any position (i,j) will have an endless column if (i+1,j) will have an endless column
and value of (i,j) is 1.
So we should maintain two matrices one for row and one for column. Always start from right most position for
row and bottom most position for column and only check for next position whether it has endless path or not.
And Finally, if any position will have an endless path in both row and column matrix then that position is said
to have an endless path.
we build a 2D array dp[][] such that dp[i][j] stores true if sum j is possible with array elements from 0 to i.
After filling dp[][], we recursively traverse it from dp[n-1][sum]. For cell being traversed, we store path before
reaching it and consider two possibilities for the element.
1) Element is included in current path.
2) Element is not included in current path.
Whenever sum becomes 0, we stop the recursive calls and print current path.
http://www.geeksforgeeks.org/perfect-sum-problem-print-subsets-given-sum/
see code
Subset with sum divisible by m
Given a set of non-negative distinct integers, and a value m, determine if there is a subset of the given set
with sum divisible by m.
f n > m there will always be a subset with sum divisible by m (which is easy to prove with pigeonhole
principle). So we need to handle only cases of n <= m .
For n <= m we create a boolean DP table which will store the status of each value from 0 to m-1 which are
possible subset sum (modulo m) which have been encountered so far.
Now we loop through each element of given array arr[], and we add (modulo m) j which have DP[j] = true and
store all the such (j+arr[i])%m possible subset sum in a boolean array temp, and at the end of iteration over j,
we update DP table with temp. Also we add arr[i] to DP ie.. DP[arr[i]%m] = true.
In the end if DP[0] is true then it means YES there exist a subset with sum which is divisible by m, else NO.
To consider all subsets of items, there can be two cases for every item: (1) the item is included in the optimal
subset, (2) not included in the optimal set.
Therefore, the maximum value that can be obtained from n items is max of following two values.
1) Maximum value obtained by n-1 items and W weight (excluding nth item).
2) Value of nth item plus maximum value obtained by n-1 items and W minus weight of the nth item (including
nth item).
If weight of nth item is greater than W, then the nth item cannot be included and case 1 is the only possibility.
Time Complexity: O(nW) where n is the number of items and W is the capacity of knapsack.
Length of the longest substring without repeating
characters
Given a string, find the length of the longest substring without repeating characters. For example, the longest
substrings without repeating characters for “ABDEFGABEF” are “BDEFGA” and “DEFGAB”, with length 6.
The idea is to scan the string from left to right, keep track of the maximum length Non-Repeating Character
Substring (NRCS) seen so far. Let the maximum length be max_len. When we traverse the string, we also
keep track of length of the current NRCS using cur_len variable. For every new character, we look for it in
already processed part of the string (A temp array called visited[] is used for this purpose). If it is not present,
then we increase the cur_len by 1. If present, then there are two cases:
a) The previous instance of character is not part of current NRCS (The NRCS which is under process). In this
case, we need to simply increase cur_len by 1.
b) If the previous instance is part of the current NRCS, then our current NRCS changes. It becomes the
substring staring from the next character of previous instance to currently scanned character. We also need to
compare cur_len and max_len, before changing current NRCS (or changing cur_len).
cur_len = i - prev_index;
}
Time Complexity: O(n + d) where n is length of the input string and d is number of characters in input string
alphabet. For example, if string consists of lowercase English characters then value of d is 26.
Auxiliary Space: O(d)
From a given cell, we are allowed to move to cells (i+1, j) and (i, j+1) only.
// If there are more than two characters, and first and last
// characters are same
Else L(i, j) = L(i + 1, j - 1) + 2
Time Complexity of the above implementation is O(n^2) which is much better than the worst case time
complexity of Naive Recursive implementation.
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?
The problem is not actually to find the critical floor, but merely to decide floors from which eggs should be
dropped so that total number of trials are minimized.
In this post, we will discuss solution to a general problem with n eggs and k floors. The solution is to try
dropping an egg from every floor (from 1 to k) and recursively calculate the minimum number of droppings
needed in worst case. The floor which gives the minimum value in worst case is going to be part of the
solution.
In the following solutions, we return the minimum number of trials in worst case; these solutions can be easily
modified to print floor numbers of every trials also.
1) Optimal Substructure:
When we drop an egg from a floor x, there can be two cases (1) The egg breaks (2) The egg doesn’t break.
1) If the egg breaks after dropping from xth floor, then we only need to check for floors lower than x with
remaining eggs; so the problem reduces to x-1 floors and n-1 eggs
2) If the egg doesn’t break after dropping from the xth floor, then we only need to check for floors higher than
x; so the problem reduces to k-x floors and n eggs.
Since we need to minimize the number of trials in worst case, we take the maximum of two cases. We
consider the max of above two cases for every floor and choose the floor which yields minimum number of
trials.
1. Start Time
2. Finish Time
3. Profit or Value Associated
Find the maximum profit subset of jobs such that no two jobs in the subset overlap.
A simple version of this problem is discussed here where every job has same profit or value. The Greedy
Strategy for activity selection doesn’t work here as a schedule with more jobs may have smaller profit or
value.
Time Complexity of the above Dynamic Programming Solution is O(n2). Note that the above solution can be
optimized to O(nLogn) using Binary Search in latestNonConflict() instead of linear search.
The above program only prints the shortest distances. We can modify the solution to print the shortest paths
also by storing the predecessor information in a separate 2D matrix.
Partition problem
Partition problem is to determine whether a given set can be partitioned into two subsets such that the sum of
elements in both subsets is same.
Following are the two main steps to solve this problem:
1) Calculate sum of the array. If sum is odd, there can not be two subsets with equal sum, so return false.
2) If sum of array elements is even, calculate sum/2 and find a subset of array with sum equal to sum/2.
The problem can be solved using dynamic programming when the sum of the elements is not too big. We can
create a 2D array part[][] of size (sum/2)*(n+1). And we can construct the solution in bottom up manner such
that every filled entry has following property
Variations of LIS
We have discussed Dynamic Programming solution for Longest Increasing Subsequence problem in this post
and a O(nLogn) solution in this post. Following are commonly asked variations of the standard LIS problem.
1. Building Bridges: Consider a 2-D map with a horizontal river passing through its center. There are n
cities on the southern bank with x-coordinates a(1) … a(n) and n cities on the northern bank with x-
coordinates b(1) … b(n). You want to connect as many north-south pairs of cities as possible with bridges
such that no two bridges cross. When connecting cities, you can only connect city i on the northern bank
to city i on the southern bank.
Source: Dynamic Programming Practice Problems. The link also has well explained solution for the problem.
2. Maximum Sum Increasing Subsequence: Given an array of n positive integers. Write a program to find
the maximum sum subsequence of the given array such that the intgers in the subsequence are sorted in
increasing order. For example, if input is {1, 101, 2, 3, 100, 4, 5}, then output should be {1, 2, 3, 100}. The
solution to this problem has been published here.
3. The Longest Chain You are given pairs of numbers. In a pair, the first number is smaller with respect to
the second number. Suppose you have two sets (a, b) and (c, d), the second set can follow the first set if b <
c. So you can form a long chain in the similar fashion. Find the longest chain which can be formed. The
solution to this problem has been published here.
4. Box Stacking You are given a set of n types of rectangular 3-D boxes, where the i^th box has height h(i),
width w(i) and depth d(i) (all real numbers). You want to create a stack of boxes which is as tall as possible,
but you can only stack a box on top of another box if the dimensions of the 2-D base of the lower box are
each strictly larger than those of the 2-D base of the higher box. Of course, you can rotate a box so that any
side functions as its base. It is also allowable to use multiple instances of the same type of box.
1) Generate all 3 rotations of all boxes. The size of rotation array becomes 3 times the size of original array.
For simplicity, we consider depth as always smaller than or equal to width.
4) To get overall maximum height, we return max(MSH(i)) where 0 < i < n
Bellman–Ford Algorithm
Given a graph and a source vertex src in graph, find shortest paths from src to all vertices in the given graph.
The graph may contain negative weight edges.
We have discussed Dijkstra’s algorithm for this problem. Dijksra’s algorithm is a Greedy algorithm and time
complexity is O(VLogV) (with the use of Fibonacci heap). Dijkstra doesn’t work for Graphs with negative
weight edges, Bellman-Ford works for such graphs. Bellman-Ford is also simpler than Dijkstra and suites well
for distributed systems. But time complexity of Bellman-Ford is O(VE), which is more than Dijkstra.
lgorithm
Following are the detailed steps.
Input: Graph and a source vertex src
Output: Shortest distance to all vertices from src. If there is a negative weight cycle, then shortest distances
are not calculated, negative weight cycle is reported.
1) This step initializes distances from source to all vertices as infinite and distance to source itself as 0.
Create an array dist[] of size |V| with all values as infinite except dist[src] where src is source vertex.
2) This step calculates shortest distances. Do following |V|-1 times where |V| is the number of vertices in
given graph.
…..a) Do following for each edge u-v
………………If dist[v] > dist[u] + weight of edge uv, then update dist[v]
………………….dist[v] = dist[u] + weight of edge uv
3) This step reports if there is a negative weight cycle in graph. Do following for each edge u-v
……If dist[v] > dist[u] + weight of edge uv, then “Graph contains negative weight cycle”
The idea of step 3 is, step 2 guarantees shortest distances if graph doesn’t contain negative weight cycle. If
we iterate through all edges one more time and get a shorter path for any vertex, then there is a negative
weight cycle
How does this work? Like other Dynamic Programming Problems, the algorithm calculate shortest paths in
bottom-up manner. It first calculates the shortest distances for the shortest paths which have at-most one
edge in the path. Then, it calculates shortest paths with at-nost 2 edges, and so on. After the ith iteration of
outer loop, the shortest paths with at most i edges are calculated. There can be maximum |V| – 1 edges in
any simple path, that is why the outer loop runs |v| – 1 times. The idea is, assuming that there is no negative
weight cycle, if we have calculated shortest paths with at most i edges, then an iteration over all edges
guarantees to give shortest path with at-most (i+1) edges (Proof is simple, you can refer this or MIT Video
Lecture)
Notes
1) Negative weights are found in various applications of graphs. For example, instead of paying cost for a
path, we may get some advantage if we follow the path.
2) Bellman-Ford works better (better than Dijksra’s) for distributed systems. Unlike Dijksra’s where we need to
find minimum value of all vertices, in Bellman-Ford, edges are considered one by one.
Let us first define the cost of a BST. The cost of a BST node is level of that node multiplied by its frequency.
Level of root is 1.
1) Optimal Substructure:
The optimal cost for freq[i..j] can be recursively calculated using following formula.
The idea of above formula is simple, we one by one try all nodes as root (r varies from i to j in second term).
When we make rth node as root, we recursively calculate optimal cost from i to r-1 and r+1 to j.
We add sum of frequencies from i to j (see first term in the above formula), this is added because every
search will go through root and one comparison will be done for every search.
Notes
1) The time complexity of the above solution is O(n^4). The time complexity can be easily reduced to O(n^3)
by pre-calculating sum of frequencies instead of calling sum() again and again.
2) In the above solutions, we have computed optimal cost only. The solutions can be easily modified to store
the structure of BSTs also. We can create another auxiliary array of size n to store the structure of tree. All we
need to do is, store the chosen ‘r’ in the innermost loop.
Let LISS(X) indicates size of largest independent set of a tree with root X.
Let the input string be str[l……h]. The problem can be broken down into three parts:
1. Find the minimum number of insertions in the substring str[l+1,…….h].
2. Find the minimum number of insertions in the substring str[l…….h-1].
3. Find the minimum number of insertions in the substring str[l+1……h-1].
abcda: Number of insertions required is 2. adcbcda which is same as number of insertions in the substring
bcd(Why?).
Recursive Solution
The minimum number of insertions in the string str[l…..h] can be given as:
minInsertions(str[l+1…..h-1]) if str[l] is equal to str[h]
min(minInsertions(str[l…..h-1]), minInsertions(str[l+1…..h])) + 1 otherwise
Time complexity of this method is also O(n^2) and this method also requires O(n^2) extra space.
An efficient approach uses the concept of finding the length of the longest palindromic subsequence of a given
sequence.
Algorithm:
-->str is the given string.
-->n length of str
-->len be the length of the longest
palindromic subsequence of str
-->// minimum number of deletions
min = n - len
This problem is similar to Rod Cutting Problem. We can get the maximum product by making a cut at different
positions and comparing the values obtained after a cut. We can recursively call the same function for a piece
obtained after a cut.
Let maxProd(n) be the maximum product for a rope of length n. maxProd(n) can be written as following.
A Tricky Solution:
If we see some examples of this problems, we can easily observe following pattern.
The maximum product can be obtained be repeatedly cutting parts of size 3 while size is greater than 4,
keeping the last part as size of 2 or 3 or 4. For example, n = 10, the maximum product is obtained by 3, 3, 4.
For n = 11, the maximum product is obtained by 3, 3, 3, 2
Time Complexity: Having the three simple loops, the complexity of the above algorithm is .
Examples:
Input: n = 2
Output: 1
For two elements say {0, 1}, there is only one
possible derangement {1, 0}
Let countDer(n) be count of derangements for n elements. Below is recursive relation for it.
Let 0 be placed at index i. There are now two possibilities, depending on whether or not element i is placed
at 0 in return.
1. i is placed at 0: This case is equivalent to solving the problem for n-2 elements as two elements have
just swapped their positions.
2. i is not placed at 0: This case is equivalent to solving the problem for n-1 elements as now there are
n-1 elements, n-1 positions and every element has n-2 choices
Time Complexity: O(n)
Auxiliary Space: O(n)
Dice Throw)
Given n dice each with m faces, numbered from 1 to m, find the number of ways to get sum X. X is the
summation of values on each face when all the dice are thrown.
Let the function to find X from n dice is: Sum(m, n, X)
The function can be represented as:
Sum(m, n, X) = Finding Sum (X - 1) from (n - 1) dice plus 1 from nth dice
+ Finding Sum (X - 2) from (n - 1) dice plus 2 from nth dice
+ Finding Sum (X - 3) from (n - 1) dice plus 3 from nth dice
...................................................
...................................................
...................................................
+ Finding Sum (X - m) from (n - 1) dice plus m from nth dice
Time Complexity: O(m * n * x) where m is number of faces, n is number of dice and x is given sum.
We can add following two conditions at the beginning of findWays() to improve performance of program for
extreme cases (x is too high or x is too low)
Following is recursive solution that is based on above two choices. We take the maximum of two choices.
F(i, j) represents the maximum value the user can collect from
i'th coin to j'th coin.
Input: ilike
Output: Yes
The string can be segmented as "i like".
Input: ilikesamsung
Output: Yes
The string can be segmented as "i like samsung"
or "i like sam sung".
The above solutions only finds out whether a given string can be segmented or not. Extend the above
Dynamic Programming solution to print all possible partitions of input string.
Refer below post for solution of exercise.
Word Break Problem using Backtracking
Further Optimizations:
The above code can be optimized in many ways.
1) We can avoid calculation of min() and/or max() when min and/or max is/are not changed by removing
corner elements.
2) We can pre-process the array and build segment tree in O(n) time. After the segment tree is built, we can
query range minimum and maximum in O(Logn) time. The overall time complexity is reduced to O(n2Logn)
time.
A O(n^2) Solution
The idea is to find the maximum sized subarray such that 2*min > max. We run two nested loops, the outer
loop chooses a starting point and the inner loop chooses ending point for the current starting point. We keep
track of longest subarray with the given property.
If we take a closer look at the pattern, we can observe that the count is actually (n+2)’th Fibonacci number for
n >= 1. The Fibonacci Numbers are 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 141, ….
n = 1, count = 2 = fib(3)
n = 2, count = 3 = fib(4)
n = 3, count = 5 = fib(5)
n = 4, count = 8 = fib(6)
n = 5, count = 13 = fib(7)
Therefore we can count the strings in O(Log n) time also using the method 5 here.
This problem is recursive and can be broken in sub-problems. We start from end of the given digit sequence.
We initialize the total count of decodings as 0. We recur for two subproblems.
1) If the last digit is non-zero, recur for remaining (n-1) digits and add the result to total count.
2) If the last two digits form a valid character (or smaller than 27), recur for remaining (n-2) digits and add the
result to total count.
the recursive solution is similar to Fibonacci Numbers. Therefore, we can optimize the above solution to work
in O(n) time using Dynamic Programming.
Time Complexity of the above solution is O(n) and it requires O(n) auxiliary space. We can reduce auxiliary
space to O(1) by using space optimized version discussed in the Fibonacci Number Post.
The graph is given as adjacency matrix representation where value of graph[i][j] as 1 indicates that there is an
edge from vertex i to vertex j and a value 0 indicates no edge from i to j.
The idea is to build a 3D table where first dimension is source, second dimension is destination, third
dimension is number of edges from source to destination, and the value is count of walks. Like other Dynamic
Programming problems, we fill the 3D table in bottom up manner.
Time complexity of the above DP based solution is O(V3K) which is much better than the naive solution.
We can also use Divide and Conquer to solve the above problem in O(V3Logk) time. The count of walks of
length k from u to v is the [u][v]’th entry in (graph[V][V])k. We can calculate power of by doing O(Logk)
multiplication by using the divide and conquer technique to calculate power. A multiplication between two
matrices of size V x V takes O(V3) time. Therefore overall time complexity of this method is O(V3Logk).
The idea is to consider following two possibilities for root and recursively for all nodes down the root.
1) Root is part of vertex cover: In this case root covers all children edges. We recursively calculate size of
vertex covers for left and right subtrees and add 1 to the result (for root).
2) Root is not part of vertex cover: In this case, both children of root must be included in vertex cover to
cover all root to children edges. We recursively calculate size of vertex covers of all grandchildren and
number of children to the result (for two children of root).
In the following solution, an additional field ‘vc’ is added to tree nodes. The initial value of ‘vc’ is set as 0 for all
nodes. The recursive function vCover() calculates ‘vc’ for a node only if it is not already set.
Find the minimum cost to reach destination using a train
There are N stations on route of a train. The train goes from station 0 to N-1. The ticket cost for all pair of
stations (i, j) is given where j is greater than i. Find the minimum cost to reach the destination.
Input:
cost[N][N] = { {0, 15, 80, 90},
{INF, 0, 40, 50},
{INF, INF, 0, 70},
{INF, INF, INF, 0}
};
There are 4 stations and cost[i][j] indicates cost to reach j
from i. The entries where j < i are meaningless.
Output:
The minimum cost is 65
The minimum cost can be obtained by first going to station 1
from 0. Then from station 1 to station 3.
We need to do less work here compared to above mentioned post as we know topological sorting of the
graph. The topological sorting of vertices here is 0, 1, ..., N-1. Following is the idea once topological sorting is
known.
The idea in below code is to first calculate min cost for station 1, then for station 2, and so on. These costs
are stored in an array dist[0...N-1].
return dist[N-1];
}
We can do this O(n) using following Efficient Solution. The idea is to store maximum possible profit of every
subarray and solve the problem in following two phases.
2) Traverse price[] from right to left and update profit[i] such that profit[i] stores maximum profit achievable
from one transaction in subarray price[i..n-1]
3) Traverse price[] from left to right and update profit[i] such that profit[i] stores maximum profit such that
profit[i] contains maximum achievable profit from two transactions in subarray price[0..i].
4) Return profit[n-1]
To do step 1, we need to keep track of maximum price from right to left side and to do step 2, we need to
keep track of minimum price from left to right. Why we traverse in reverse directions? The idea is to save
space, in second step, we use same array for both purposes, maximum with 1 transaction and maximum with
2 transactions. After an iteration i, the array profit[0..i] contains maximum profit with 2 transactions and
profit[i+1..n-1] contains profit with two transactions.
int max_price = price[n-1];
for (int i=n-2;i>=0;i--)
{
// max_price has maximum of price[i..n-1]
if (price[i] > max_price)
max_price = price[i];
N = 3
Output = 25
3 sections, which means possible ways for one side are
BSS, BSB, SSS, SBS, SSB where B represents a building
and S represents an empty space
Total possible ways are 25, because a way to place on
one side can correspond to any of 5 ways on other side.
We can simplify the problem to first calculate for one side only. If we know the result for one side, we can
always do square of the result and get result for two sides.
sum(9) = 1 + 2 + 3 + 4 ........... + 9
= 9*10/2
= 45
Algorithm: sum(n)
if (m == 0) return n;
if (n == 0) return m;
This problem is a variation of the problem discussed Coin Change Problem. Here instead of finding total
number of possible solutions, we need to find the solution with minimum number of coins.
The minimum number of coins for a value V can be computed using below recursive formula.
The idea is to first search given starting character in the given matrix. Do Depth First Search (DFS) from all
occurrences to find all consecutive paths. While doing DFS, we may encounter many subproblems again and
again. So we use dynamic programming to store results of subproblems.
static int getLenUtil(char mat[][], int i, int j, char prev)
{
// If this cell is not valid or current character is not
// adjacent to previous one (e.g. d is not adjacent to b )
// or if this cell is already included in the path than return 0.
if (!isvalid(i, j) || !isadjacent(prev, mat[i][j]))
return 0;
int ans = 0;
One way to look at the problem is, count of numbers is equal to count n digit number ending with 9 plus count
of ending with digit 8 plus count for 7 and so on. How to get count ending with a particular digit? We can recur
for n-1 length and digits smaller than or equal to the last digit. So below is recursive formula.
Count of n digit numbers = (Count of (n-1) digit numbers Ending with digit 9) +
(Count of (n-1) digit numbers Ending with digit 8) +
.............................................+
.............................................+
(Count of (n-1) digit numbers Ending with digit 0)
Let count ending with digit ‘d’ and length n be count(n, d)
Constraints :
▪ Example:
Input: points[m][n] = { {-2, -3, 3},
▪ At the first look, this problem looks similar Max/Min Cost Path, but maximum overall points gained will
not guarantee the minimum initial points. Also, it is compulsory in the current problem that the points
never drops to zero or below. For instance, Suppose following two paths exists from source to
destination cell.
We can solve this problem through bottom-up table filling dynamic programing technique.
▪ To begin with, we should maintain a 2D array dp of the same size as the grid, where dp[i][j]
represents the minimum points that guarantees the continuation of the journey to destination
before entering the cell (i, j). It’s but obvious that dp[0][0] is our final solution. Hence, for this
problem, we need to fill the table from the bottom right corner to left top.
▪ Now, let us decide minimum points needed to leave cell (i, j) (remember we are moving from
bottom to up). There are only two paths to choose: (i+1, j) and (i, j+1). Of course we will choose the
cell that the player can finish the rest of his journey with a smaller initial points. Therefore we
have: min_Points_on_exit = min(dp[i+1][j], dp[i][j+1])
▪ Now we know how to compute min_Points_on_exit, but we need to fill the table dp[][] to get the solution
in dp[0][0].
How to compute dp[i][j]?
The value of dp[i][j] can be written as below.
dp[i][j] = max(min_Points_on_exit – points[i][j], 1)
Let us see how above expression covers all cases.
▪ If points[i][j] == 0, then nothing is gained in this cell; the player can leave the cell with the same
points as he enters the room with, i.e. dp[i][j] = min_Points_on_exit.
▪ If dp[i][j] < 0, then the player must have points greater than min_Points_on_exit before entering (i,
j) in order to compensate for the points lost in this cell. The minimum amount of compensation is " -
points[i][j] ", so we have dp[i][j] = min_Points_on_exit - points[i][j].
▪ If dp[i][j] > 0, then the player could enter (i, j) with points as little as min_Points_on_exit – points[i]
[j]. since he could gain “points[i][j]” points in this cell. However, the value of min_Points_on_exit –
points[i][j] might drop to 0 or below in this situation. When this happens, we must clip the value to 1
in order to make sure dp[i][j] stays positive:
dp[i][j] = max(min_Points_on_exit – points[i][j], 1).
▪ Finally return dp[0][0] which is our answer.
The idea is simple, we subtract all values from 0 to 9 from given sum and recur for sum minus that digit.
Below is recursive formula.
// Initialize answer
int ans = 0;
return ans;
}
This problem is mainly an extension of Count of n digit numbers whose sum of digits equals to given sum.
Here the solution of subproblems depend on four variables: digits, esum (current even sum), osum (current
odd sum), isEven(A flag to indicate whether current digit is even or odd).
Constraints: 1 <= n <= 10 Since, number of ways could be large, so output modulo 1000000007
What is Bitmasking?
Suppose we have a collection of elements which are numbered from 1 to N. If we want to represent a subset
of this set than it can be encoded by a sequence of N bits (we usually call this sequence a “mask”). In our
chosen subset the i-th element belongs to it if and only if the i-th bit of the mask I set i.e., it equals to 1. For
example, the mask 10000101 means that the subset of the set [1… 8] consists of elements 1, 3 and 8. We
know that for a set of N elements there are total 2N subsets thus 2N masks are possible, one representing
each subset. Each mask is in fact an integer number written in binary notation.
The idea is to use the fact that there are upto 10 persons. So we can use a integer variable as a bitmask to
store which person is wearing cap and which is not.
Let i be the current cap number (caps from 1 to i-1 are already
processed). Let integer variable mask indicates the the persons w
earing and not wearing caps. If i'th bit is set in mask, then
i'th person is wearing a cap, else not.
Since we want to access all persons that can wear a given cap, we use an array of vectors, capList[101]. A
value capList[i] indicates the list of persons that can wear cap i.
// So, assign one by one ith cap to all the possible persons
// and recur for remaining caps.
for (int j = 0; j < size; j++)
{
// if person capList[i][j] is already wearing a cap so continue as
// we cannot assign him this cap
if ((mask & (1 << capList[i].get(j))) != 0) continue;
// Else assign him this cap and recur for remaining caps with
// new updated mask vector
else ways += countWaysUtil(mask | (1 << capList[i].get(j)), i+1);
ways %= MOD;
}
System.out.println(countWaysUtil(0, 1));
This problem is just the modification of Longest Common Subsequence problem. The idea is to find
theLCS(str, str)where str is the input string with the restriction that when both the characters are
same, they shouldn’t be on the same index in the two strings.
if (str.charAt(i-1) == str.charAt(j-1) && i!=j)
dp[i][j] = 1 + dp[i-1][j-1];
// If characters do not match
else
dp[i][j] = Math.max(dp[i][j-1], dp[i-1][j]);
We can move in 4 directions from a given cell (i, j), i.e., we can move to (i+1, j) or (i, j+1) or (i-1, j) or (i, j-1)
with the condition that the adjacent cells have a difference of 1.
The idea is simple, we calculate longest path beginning with every cell. Once we have computed longest for
all cells, we return maximum of all longest paths. One important observation in this approach is many
overlapping subproblems. Therefore this problem can be optimally solved using Dynamic Programming.
Below is Dynamic Programming based implementation that uses a lookup table dp[][] to check if a problem is
already solved or not.
Time complexity of the above solution is O(n2). It may seem more at first look. If we take a closer look, we can
notice that all values of dp[i][j] are computed only once.
return result;
}
1. Move one step ahead, i.e., cell (i, j-1) and direction remains left.
2. Move one step down and face right, i.e., cell (i+1, j) and direction becomes right.
4. Final position can be anywhere and final direction can also be anything. The target is to collect
maximum coins.
// Initialize result
If (arr[i][j] == 'C')
result = 1;
Else
result = 0;
If (d == 0) // Left direction
return result + max(maxCoins(i+1, j, 1), // Down
maxCoins(i, j-1, 0)); // Ahead in left
If (d == 1) // Right direction
return result + max(maxCoins(i+1, j, 1), // Down
maxCoins(i, j+1, 0)); // Ahead in right
1. Time Complexity of above solution is O(R x C x d). Since d is 2, time complexity can be written as O(R x
C).
// Base cases