Algorithms and Problem Solving (15B11CI411) : EVEN 2022
Algorithms and Problem Solving (15B11CI411) : EVEN 2022
EVEN 2022
M[0]=0
int coin_change(int d[], int sum, int n) { J=1: min = inf
i=1: 1=1 min=1+M[0] = 1
int M[sum+1];
i=2: 1<2
M[0] = 0; i=3: 1<3
int i, j; M[1]=1
for(j=1; j<=sum; j++) { J=2: min = inf
i=1: 2>1 min=1+M[1] = 2
int min = INF; i=2: 2=2 min=1+M[0] = 1
for(i=1; i<=n; i++) { i=3: 2<3
if(j >= d[i]) { M[2]=1
min = MIN(min, 1+M[j-d[i]]); J=3: min = inf
i=1: 3>1 min=1+M[2] = 2
} i=2: 3>2 min=1+M[1] = 2
} i=3: 3=3 min=1+M[0] = 1
M[j] = min; M[3]=1
J=4: min = inf
}
i=1: 4>1 min=1+M[3] = 2
return M[n]; i=2: 4>2 min=1+M[2] = 2
} i=3: 4>3 min=1+M[1] = 2
M[4]=2
J=5: min = inf
i=1: 5>1 min=1+M[4] = 3
T(n) = O(n*sum)
i=2: 5>2 min=1+M[3] = 2
i=3: 5>3 min=1+M[2] = 2
How to obtain which coins are in the solution?
d[] = {0, 1, 2, 3} \\ first value is 0, we have n=3 denominations
int coin_change_modified(int d[], int sum, int n) { Sum = 5
int M[sum+1]; M[0] = 0;
int S[sum+1]; S[0] = 0; M[0]=0, S[0]=0
int i, j; J=1: min = inf, coin=0
for(j=1; j<=sum; j++) { i=1: 1=1 min=1+M[0] = 1, coin=1
int min = INF; i=2: 1<2
i=3: 1<3
int coin=0; M[1]=1, S[1]=1
for(i=1; i<=n; i++) { J=2: min = inf , coin=0
if(j >= d[i]) { i=1: 2>1 min=1+M[1] = 2 , coin=1
if((1+M[j-d[i]]) < min) { i=2: 2=2 min=1+M[0] = 1 , coin=2
min = 1+M[j-d[i]]; i=3: 2<3
coin = i; M[2]=1 , S[2]=2
J=3: min = inf , coin=0
}
i=1: 3>1 min=1+M[2] = 2 , coin=1
} i=2: 3>2 min=1+M[1] = 2 ,
} i=3: 3=3 min=1+M[0] = 1 , coin=3
M[j] = min; M[3]=1 , S[3]=3
S[j] = coin; J=4: min = inf , coin=0
} i=1: 4>1 min=1+M[3] = 2 , coin=1
int l = sum; i=2: 4>2 min=1+M[2] = 2
i=3: 4>3 min=1+M[1] = 2
while(l>0) {
M[4]=2 , S[4]=1
printf("%d\n",d[S[l]]); J=5: min = inf , coin=0
l = l-d[S[l]]; i=1: 5>1 min=1+M[4] = 3 , coin=1
} i=2: 5>2 min=1+M[3] = 2 , coin=2
return M[n]; i=3: 5>3 min=1+M[2] = 2
} M[5] = 2 , S[5]=2
Print 2, 3
Longest Common Subsequence problem: Given two strings, X and Y, the task is to find the length
of the longest subsequence present in both of the strings.
Example:
L() G X T X A Y B
For X = “AGGTAB”, Y = “GXTXAYB”
A 0 0 0 0 1 0 0
Output: 4 (GTAB) G 1 1 1 1 1 1 1
Let input X[0…m-1], Y[0…n-1] and G 1 1 1 1 1 1 1
T 0 1 2 2 2 2 2
L(X[0…m-1], Y[0…n-1]) be the length of the LCS of X and Y. A 0 1 2 2 3 3 3
B 0 1 2 2 3 3 4
Recurssive solution:
• If the last characters of both sequences match (X[m-1] == Y[n-1]) then
L(X[0…m-1], Y[0…n-1]) = 1 + L(X[0…m-2], Y[0…n-2])
• If last characters of both sequences do not match then
L(X[0…m-1], Y[0…n-1]) = MAX ( L(X[0…m-2], Y[0…n-1]), L(X[0…m-1], Y[0…n-2]) )
int lcs(string X, string Y, int m, int n)
{
int L[m + 1][n + 1];
// Build L[m+1][n+1] in bottom up fashion. Note that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1]
Recursive solution:
• Consider two pointers i and j pointing the end of given string A and B.
• If the current character, pointing in both the strings are same, then no changes are to be made.
Therefore, recurse for lengths i - 1 and j - 1.
• Otherwise, try to apply the operations provided.
• Each of the given operations would cause 1 units.
• For insertion: Recurse i to j-1.
• For deletion: Recurse i-1 to j .
• For replacement: Recurse i – 1 to j – 1.
• After applying all the operations, f(i, j) = 1 + min(f(i, j-1), f(i-1, j), f(i – 1, j – 1)).
int editDist(string str1, string str2, int i, int j) Example 1: str1 = llo, str2 = hello
i=3,j=5 i=2,j=4 i=1,j=3 i=0,j=2
{
i o, j o: i l, j l: i l, j l: return 2 (he will be
// If first string is empty, the only option is to insert all characters of inserted in str1 to make it hello)
second string into first or vice-versa
if (i == 0) Example 2: str1 = hollo, str2 = hello
i=5,j=5 i=4,j=4 i=3,j=3 i=2,j=2
return j; i o, j o: i l, j l: i l, j l:
if (j == 0) return 1+ min(eD(2,1), eD(1,2), eD(1,1)) = 1+0 = 1 (e
will be replaced for o)
return i;
eD(2,1): i=2,j=1 1+min(eD(2,0),eD(1,1),eD(1,0))
/* If last characters of two strings are same, ignore last characters and 1+min(2, eD(0,0), 1)
get count for remaining strings */ 1+min(2, 0, 1) = 1
if (str1[i - 1] == str2[j - 1]) eD(1,2): i=1,j=2 1+min(eD(1,1),eD(0,2),eD(0,1))
1+min(0, 2, 1) = 1
return editDist(str1, str2, i - 1, j - 1);
eD(1,1) = 0
/* If last characters are not same, consider all three operations on last
character of first string, recursively compute minimum cost for all
three operations and take minimum of three values. */
T(i) = O(3^i) – worst case when none of the
return 1 + min(editDist(str1, str2, i, j - 1), // Insert characters of both the strings match
editDist(str1, str2, i - 1, j), // Remove
editDist(str1, str2, i – 1, j - 1) // Replace
); Overlapping Subproblems Dynamic Programming
}
void EditDistDP(string str1, string str2) {
int len1 = str1.length(); int len2 = str2.length();
int DP[2][len1 + 1];
memset(DP, 0, sizeof DP);
for (int i = 0; i <= len1; i++)
DP[0][i] = i;
// For every character in second string
for (int i = 1; i <= len2; i++) {
for (int j = 0; j <= len1; j++) {
// if first string is empty then add character to get second string
if (j == 0)
DP[i % 2][j] = i;
// if character from both string is same then we do not perform any operation. i % 2 is to bound the row number.
else if (str1[j - 1] == str2[i - 1])
DP[i % 2][j] = DP[(i - 1) % 2][j - 1];
// if character from both string is not same then we take the minimum from three specified operation
else {
DP[i % 2][j] = 1 + min(DP[(i - 1) % 2][j], min(DP[i % 2][j - 1], DP[(i - 1) % 2][j - 1]));
}
}
}
// Fill the DP array if the len2 is even then we end up in the 0th row else we end up in the 1th row so we take len2 % 2 to get row
cout << DP[len2 % 2][len1] << endl;
}
Few more practice problems:
• Print all possible ways to convert one string into another string.
• Write a function that takes two parameters n and k and returns the value of Binomial Coefficient C(n, k). For
example, your function should return 6 for n = 4 and k = 2, and it should return 10 for n = 5 and k = 2.
• Hint: C(n, k) = C(n-1, k-1) + C(n-1, k) and C(n, 0) = C(n, n) = 1
• Given n eggs and k floors, find the minimum number of trials needed in worst case to find critical floor (the
floor below which all floors are safe). A floor is safe if dropping an egg from it does not break the egg.
• K Number of floors, N Number of Eggs, and eggDrop(N, K) Minimum number of trials needed to find
the critical floor in worst case.
• eggDrop(N, K) = 1 + min{max{eggDrop(N – 1, x – 1), eggDrop(N, K – x)}}, where x is in {1, 2, …, K}
• eggDrop(3,3) = 1+min{max(eggDrop(2,0), eggDrop(3,1)),max(eggDrop(2,1),eggDrop(3,1)),max(eggDrop(2,2),eggDrop(3,0))}
= 1+min{1,1,2} = 2
eggDrop(2,0) = 0, eggDrop(3,1) = 1, eggDrop(2, 1) = 1,eggDrop(3,1) = 1, eggDrop(3,0) = 0
eggDrop(2,2) = 1+min{max{(eggDrop(1,0), eggDrop(2,1)),(eggDrop(2, 1),eggDrop(2,0))}} = 1+min{max{(0,1),(1,0)} = 2
Few more practice problems:
• Longest palindromic subsequence. Example: MAYAAM has “MAYAM” or “MAAAM”
• X[0..n-1] input sequence, L(0, n-1) length of the longest palindromic subsequence of X[0..n-1].
If last and first characters of X are same, then L(0, n-1) = L(1, n-2) + 2
Else L(0, n-1) = MAX (L(1, n-1), L(0, n-2))
• Partition problem: Determine whether a given set can be partitioned into two subsets such that the sum of
elements in both subsets is the same. E.g. {1, 5, 11, 5} can be partitioned as {1, 5, 5} and {11}
• isPossible(arr, n, sum/2) be the function that returns true if there is a subset of arr[0..n-1] with sum equal
to sum/2
• Divide the problem into two subproblems:
• isPossible() without considering last element (reducing n to n-1)
• isPossible() considering the last element (reducing sum/2 by arr[n-1] and n to n-1)
• isPossible (arr, n, sum/2) = isPossible (arr, n-1, sum/2) || isPossible (arr, n-1, sum/2 – arr[n-1])