Download as pdf or txt
Download as pdf or txt
You are on page 1of 16

ALD ASSIGNMENT 5 & 6

Ritvik Gupta(2018407)

Divide and Conquer

Ans 1)
Let the 2 n-bit numbers be X and Y respectively. We are given that addition X+Y is O(n).
For efficient multiplication, we will use the ​Karatsuba Algorithm​, which is a divide and conquer
approach.
Note: At any step during dividing, If n is odd, add 0 in front of the number and proceed.
Divide both numbers into 2 equal parts. Let X divide into X1 and X2. Y divides into Y1 and Y2.
All the new numbers are n/2 bits.
The product XY can be computed as:
X*Y=(X1*2​n/2 ​+ X​2​)*(Y1*2​n/2​ + Y2)
= X1*Y1*2​n​ + 2​n/2​(X1*Y2 + Y1*X2) + X2*Y2 ___(1)
In the above case, we need to perform 4 multiplications.

Also, another thing we can write is that:


X1*Y2 + Y1*X2 = (X1+X2)*(Y1+Y2) - X1*Y1 - X2*Y2 __(2)
Now, let X1+X2 = X3 and Y1+Y2=Y3
Therefore, eqn 2 becomes:
X1*Y2 + Y1*X2 = X3*Y3- X1*Y1 - X2*Y2
Put this in equation 1,
X*Y=X1*Y1*2​n​ + 2​n/2​(X3*Y3- X1*Y1 - X2*Y2) + X2*Y2 __(3)

For equation 3, we would have to perform only 3 multiplications as compared to 4 in equation 1.


X*Y can be computed by dividing the number until we are left with 1 bit then merging the results.
And addition is done in O(n) time.

Recurrence Relation:
T(n) = 3*T(n/2) + O(n)

By Master’s Theorem, we get the time complexity for following relation as the following :
T(n) = O(n log23 ) = O(n​1.58​)

Hence this multiplication is better than normal O(n​2​) multiplication of integers.


Ans 2)
The given algorithm calculates power in ​O (log n).
// Here b>0 and a and b are integers

static int power(int a,int b){


int temp=0;
if(b==0){
return 1;
}
else if(b==1){
return a;
}
temp=power(a, b / 2);
if(b%2==0) {
return temp * temp;
}
else if(b%2==1){
return (temp * temp * a);
}
return temp * temp;
}

Proof of correctness:
By induction:

Base Case:
power(a,0): a​0​=1

Inductive Hypothesis:
Let power(a,k) returns a​k

Induction Step:
We need to prove power(a,k+1) returns a​k+1​.
If k+1 is even:
k+1 = 2m for integer m
(k+1)/2 = m
m is in the range 0 through k, by the inductive hypothesis,
power(a, m) returns a​m
power(a, k+1) returns [power(a, m)]​2
k+1 is odd:
k+1 = 2m+1 for integer m
(k+1)/2 = m
Therefore this becomes similar to the previous case.

Hence by Induction we can say that our algorithm is correct.

Ans 5)

We can solve the problem by using binary search.

static int sumGreaterThanS(int start, int end, int N, int S ){


//find the smallest subarray in range 1 to n such that sum of the
if(start>=end){
return start;
}
int mid=start+(end-start)/2;
int totalSum=N*((N+1)/2); //sum of first N terms
int midSum=mid*((mid+1)/2); //sum from 1st to the mid term
if((totalSum-midSum)<=S){
return sumGreaterThanS(start,mid,N,S);
//that means we need to consider more elements to get a bigger sum
}
else{
return sumGreaterThanS(mid+1,end,N,S);
//we have extra elements and we need to //reduce elements till start>=end
}
//At the end we will get that index where starting from the end sum is greater than S.
}
static int result(int N, int S){
return sumGreaterThanS(0,N-1,N,S);
}

The time complexity of the above algo is same as that of binary search ​O(log n)

Ans 7 )
Algorithm for finding convex hull.
Before calling the method to compute the convex hull, we sort the points by x-coordinate.
This step takes O(nlog⁡n) time.
Divide Step​: Find the point with median x-coordinate.
Since the input points are already sorted by x-coordinate, this step should take constant time.
This can be done in O(n) time.

Conquer Step: ​Call the above divide procedure recursively on both the halves and continue till
you are left with only one point on each of the divisions.

Merge Step:
Merge the two convex hulls computed by two recursive calls in the conquer step. The merge
procedure should take O(n) time. Find the min in sorted order and the max one now divides into
two halves and now recursively finds the most away element from the line joining them.
Recursively do this again and again to find the convex hull.

Hence the time complexity of our algorithm is O(n logn) due to the sorting step.

Note:
mid = low + (high - low)/2 is better to use instead of mid = (high + low)/2 as it can avoid integer
overflow which is caused by the latter one for large values.

DYNAMIC PROGRAMMING
Ans 2)
Find length of the longest alternating subsequence(LAS) starting from increasing number given
array a[ ] :
Make a (n x 2) matrix dp[ ][ ].
For 1 =< i < n, each dp[ i ][ 0 ] contains the length of LAS starting from 1 to i, such that the last
element of the sequence is greater than its previous element.
Similarly, For 1 =< i < n, each dp[ i ][ 1 ] contains the length of LAS starting from 1 to i, such that
the last element of the sequence is lesser than its previous element.

Recurrence Relation:
dp[ i ][ 0 ] = Max​k =i​k=1​(dp[ k ][ 1 ] + 1) where a[k]<a[i] ----(1)
dp[ i ][ 1 ] = Max​k =i​k=1​(dp[ k ][ 0 ] + 1) where a[k]>a[i] ----(2)

For the first recurrence, If no value of k is valid in the above case, dp[ i ][ 0 ]=0, here we can’t
say the answer to be 1 as the constraint that the resultant subsequence must start from
increasing number would be violated.
For the second recurrence, If no value of k is valid in the above case, dp[ i ][ 0 ]=1,because we
have now considered it as a sequence that ends with decreasing relation at its end. We can add
a greater element next time and satisfy the property.
Time Complexity:
T(n)=O(n​2​)
Space Complexity=O(2*n)

Ans 3)
Algorithm:
Make a dp[] array.
Now Let dp[i] be a value that is the minimum cost to reach n from i such that (1 < i <= n). Here
dp[n]=0
So we try all the possible paths and find the minimum out of that.
So the optimal solution for this problem would be dp[1].
Optimal Cost of travelling from point i is given by :
dp[i]= min​j: i< j <= n ​(dp[j] + f​i,j​)​ where f​i,j ​is the cost of going from i to j.

Proof of Optimality:
Canoe starts from station 1 and then we have considered all possible cases(i+1,i+2… ,n) of
canoe to reach n and then found the minimum out of it. Therefore, this approach leads to an
optimal solution.
Time Complexity:
Cost of calculating each dp[i] subproblem is O(n) hence the overall time complexity for n
subproblems is ​O(n​2​).

Ans 5)

static int coinChange(int n, int[] arr){


//Find the total number of ways of making n using the values in given array
int k=arr.length;

int[][] dp=new int[k][n+1];


for(int i=0;i<k;i++){
dp[i][0]=1; //all 0 can be done in 1 way
}
for(int i=1;i<n+1;i++) {
if(i<arr[0]){
dp[0][i]=0;
}
else if (i % arr[0] == 0) {
dp[0][i] = 1;
} else {
dp[0][i] = 0;
}
}
for(int i=1; i<k ; i++ ){
for(int j=1; j<n+1 ; j++){
if(arr[i]>j){
dp[i][j]=dp[i-1][j];
}
else{
dp[i][j]=dp[i-1][j]+dp[i][j-arr[i]];
}
}
}
return dp[k-1][n]; // total number of ways to make change
}

Time Complexity: O(n*k) Due to the 2 for loops. For loop of length k is nested inside loop of
length n.
Space Complexity: Made 2-D dp array so its cost is O(n*k)

Proof of Correctness of the the Coin Change Problem:


Let d​i​ be a coin in the set: D={d​1​,d​2​,...d​n​}
The idea is to make change for n cents, hence the optimal solution must make some
denomination d​i​. Therefore what we are exactly doing is that we are making an optimal solution
for the amount (n-d​i​) and then adding one coin of d​i ​ to it.
We don’t know which d​i​ would make the optimal solution so we try all of them, assuming that we
know how to make change for < n value.
We simply keep count of each possible way to get n and return it as our answer.

Ans 7)
This problem is based on the Longest Increasing subsequence problem.
DP Algorithm:
1) Generate a new dimensions array containing the length width and height of the boxes.
Sort the above generated array on the basis of the base area of all n boxes(i.e. Length
and width dimensions). Give priority in Area of base> Length > width in order to resolve
collisions

2) Now we just need to find the longest increasing subsequence(LIS) for the dimensions
array based on the priority.

3) Dp Approach for LIS:


Msh[i] here is => Maximum possible Stack Height with box i at top of stack
msh[i] = [ Max ( msh[j] ) + height(i) ] where j < i & (width(j) > width(i)) & (depth(j) >
depth(i))
If there is no such j then msh[i] = height(i)
4) The final solution is Max(msh[i]), where 0=< i =<n

Time Complexity:​ O(n​2​) due to 2 for loops. For each point in msh[], we need to do a
maximum of ​O​(​n​) work for each entry and there are n entries.

Space Complexity:​ O(n) due to additional array

STABLE MARRIAGE AND RECURSION

Ans 1)
a.)Yes (B1:G1, B2:G2, B3:G3, B4:G4) will be a stable matching.
This is because there are no blocking pairs, that implies there is no leverage for a man and
woman in different relationships to break their current relationships respectively and form one
itself.

b)
Yes they are not man optimal and man pessimal as they are not formed according to the stable
marriage algorithm.
Giving G1 and G2 their first choices, that means marrying (B1, G2) and (B2, G1)
would also be stable. But with this switch, B1 does worse.
So the stable matching above is not man-pessimal.
The correct man pessimal match given in part ( c )
Likewise, after marrying off the first two men and women, giving B3 and B4 their best remaining
choices, that is, marrying (B3, G4),(B4, G3), will also be stable. But after this switch, B3 does
better. So the stable matching above is not man-optimal.
The correct man optimal match is given below.

c)
Pairs according to stable marriage algorithm should have been formed as:
Man optimal:
B1 : G1
B2 : G2
B3 : G4
B4 : G3
Man pessimal:
G1 : B2
G2 : B1
G3 : B3
G4 : B4

Ans 2) Given a string and an integer k, find out whether on removing k characters from the
string, it becomes a palindrome or not.
Pseudocode for the recursive algorithm​:
#Helper recursive function
def kPalcompare(s1, s2, int m, int n):
#s1 and s2 are 2 strings. m and n are lengths respectively
if(m==0):
return n
elif(n==0):
return m
if (s1[m-1] == s2[n-1]):
return kPalcompare(s1, s2, m-1, n-1)
return (1+min(kPalcompare(s1, s2, m-1, n),kPalcompare(s1, s2, m, n-1)))
#boolean function
def kPal(str,k):
rev=str[: :-1]
x=len(str)
return (kPalcompare(str, rev, x, x) <=( k * 2))

This is an inefficient algorithm having time complexity of O(2​n​) and a DP approach would give
an efficient solution.

Ans 4)
We can solve this problem by modifying the longest common subsequence algo a bit.
Longest Repeating Subsequence:

Algorithm:
Find LCS(str,str) keeping care when both the characters are same, their index should not be at
the same position in the 2 strings.

def findLRS( X, m, n):

dp = [[0 for i in range(1000)] for j in range(1000)]


if(dp[m][n]!=-1):
return dp[m][n]

if (m == 0 or n == 0):
dp[m][n] = 0
return dp[m][n]

if (X[m - 1] == X[n - 1] and m != n):


dp[m][n] = findLRS(X, m - 1, n - 1) + 1
return dp[m][n]

dp[m][n] = max (findLRS(X, m, n - 1), findLRS(X, m - 1, n)) # Recursive step.


return dp[m][n]

Ans 5)

int isBST(node root)


{
if (root == NULL)
return(true);

if (root.left!=NULL && (maxNode(root.left) > (root.data))){


return(false); //maxNode returns value of max value node in the subtree
}
if (root.right!=NULL && minNode(root.right) < root.data) {
return(false); //maxNode returns value of min value node in the subtree
}
if (!isBST(root.left) || (!isBST(root.right))) {
return(false);
}
return(true);
}

int largestBST(node root)


{
if (isBST(root)) {
return countnodes(root);
}
else{
return max(largestBST(root.left), largestBST(root.right));
}
}
GREEDY ALGORITHM

Ans 1)
We are going to solve this problem using a greedy approach. We are given n points in the
Set A : (a​1​,a​2​,....a) on the real line in ascending order. Consider the interval [a​1 ,​ a​1​+1] first
check whether a​2​ lies within the same interval and keep moving till you get a point that lies
outside the current interval. Remove all those points which lie in the considered interval. Now
move to the next point present in the set and follow the same approach till all the points are
removed from the set.
The overall time complexity for this algo is O(n).

Proof of Correctness:

Greedy Choice Property proof:


​Let S be the optimal solution other than our greedy solution S’. Let S place it’s leftmost interval
at [x , x+1]. Now because our greedy choice in S’ is such that x​1​ has to be the maximum starting
value because x​1​ lies in the set itself, x<= x​1​ . So now we can say that all points in the set X that
lie between [x , x+1] must also lies between [ x​1 ,​ x​1​+1]. This is because the region that is
covered by [x , x+1] and not by [x​1​,x​1​+1] is [x,x​1​) But because x​1 is
​ the smallest element in the
set, no point lies in [x,x​1​). This argument can be extended to all the points and hence we can
say the S’ is an optimal solution.

Optimal Substructure proof:


Let P be the original problem with an optimal solution S. After including the interval [ x​1 ​, x​1​+1],
the subproblem P’ is to find a solution for covering the points to the right side of x​1​+1. Let S’ be
an optimal solution to P’.
Since, cost(S) = cost(S’) + 1, clearly an optimal solution to P includes within it an optimal
solution to P’.

Ans 2)

Algo:
Start at A.
Our intuitive greedy approach would be to travel as far as we can without stopping at a gas
station.
We are given a list of distances d​i​ for a city c​i ​ and the maximum miles m the car can cover after
refueling.
So, stop at gas station c​i​ such that d​i​<=m and d​i+1​>m.
Let the corresponding distance for each stop s​i​ be t​i​.
Pseudocode:
S={ }
last =0
For i in range(1,n):
If (d​i​-last)>m :
S.append(c​i-1​)
last=t​i-1
The above algorithm is O(n).

Proof Of Correctness:

Greedy Choice Property:

Let an optimal solution be S. Suppose the stops of S are in the list S: {s​1​,s​2​, . . . . . s​k​} and let the
corresponding distance for each stop be t​i​. Suppose g is the first stop made which is made by
the algorithm. We need to show that there is an optimal solution with first stop at g. If s​1​=g, then
S is a solution. Let’s assume (s​1​!=g) , so as per our greedy algo s​1​ comes before g. The total
distance in S and S’ is the same. We now argue that S’={g,s​2​, . . . . . s​k​} is an optimal solution.
Since we never ran out of gas, S’ is valid. Since S is optimal and the distance between g and s​2
is not more than s​1​ and s​2​, there is enough gas to get from g to s​2​. Rest of S and S’ are similar.

Optimal Substructure Property​:

Let P be the original problem with an optimal solution S. S. Then after stopping at the station g
at distance d​i​ the subproblem that is left over is given by {d​i+1​,d​i+2 .​ . . . d​n​}. Let S’ be an optimal
solution to P’.
Since, cost(S) = cost(S’) + 1, clearly an optimal solution to P includes within it an optimal
solution to P’.

Ans 3)
We can give a counterexample for this to prove this wrong.
Let m = 41, using the given algorithm, we get m-25=16, 16-10=6,(25*1 + 10*1 + 6*1) So we get
a total (1+1+6)=8 coins. But this is not the optimal solution, As we can achieve this in (4*10 +
1*1) i.e. using 5 coins, which would be the optimal solution.

Ans 4)
Algo:
Our greedy algo for this problem would be to put as many songs as possible(song 1 to j) on the
1st CD without exceeding the time limit of m minutes.
After that recursively do this for all the CDs till the songs are finished.
The time complexity for our algorithm is O(n), because n songs are simply added to the CDs
one by one.

Proof of Correctness:

Greedy Choice Property:


Let S be an optimal solution for which the first CD holds songs from 1 to k. Our greedy approach
adds songs from 1 to j to the first cd. We now prove there is an optimal solution which puts the j
songs on the first CD. If k==g then S is an optimal solution. Now if k is not equal to j, our greedy
algo adds the maximum possible number of songs to the first CD hence (k<j) must hold. Our
solution S’ can be constructed by moving all songs from k+1 to j on the first CD by modifying
solution S. We can prove that S’ is optimal.
The number of CD’s used by S’ <= Number of CD’s used by S. We can say that S’ is a valid
solution i.e. no CD contains songs more than m minutes. S is a valid solution all of the CDs in it
hold at most m minutes. As CD 1 in S’ has more number of songs than CD 1 in S and S is valid,
a lesser number of songs are left for the other CD’s in S’. Hence S’ is also a valid and optimal
solution.

Optimal Substructure Property:


Let P be the original problem with optimal solution S. Then after putting songs 1 to j on the first
CD , let P’ be the sub problem of songs (j + 1) to n. Let S’ be an optimal solution to P’ .
Since, cost(S) = cost(S’) + 1, so an optimal solution to P includes within it an optimal solution to
P’.

ASYMPTOTIC ANALYSIS

Ans 3)
Given f(n) and g(n) are monotonically increasing functions.
So if m<=n,
Then f(m)<=f(n) __(1)
and g(m)<=g(n) __(2)
By definition of monotonicity.
Therefore, adding both equations: f(m)+g(m) <= f(n)+g(n), hence f(n)+g(n) is monotonically
increasing.

Replace both m and n with g(m) and g(n) in equation (1) the inequality does not get affected as f
is non negative and f and g are both monotonic.
So we get f(g(m)) <= f(g(n))

Hence f(g) is monotonically increasing.


As both f and g are non-negative functions,
We can multiply both (1) and (2) to get:

f(m).g(m) <= f(n).g(n)

Hence f(n)+g(n) and f(n).g(n) are monotonically increasing functions.

Ans 4)
a) Due to one for loop running time of this code segment is Θ(n)

b) Pseudocode to implement the naive polynomial-evaluation algorithm that computes 


each term of the polynomial from scratch​ :

p-evaluate( int n , int[ ] a):


y=0
For i in range(0,n):
temp=1
For j in range(0,i):
temp=temp * x
y=y + (a[i]*temp)
c)
Initialization:
Initially, summation has no terms hence y = 0.

Maintenance:
After the ith iteration,
n−(i+1)
y=a​i​ + x ∑ a​k+i+1​x​k
k=0
n−(i+1)
= a​i​ x​0​ + ∑ a​k+i+1​ x​k+1
k=0

n−i
= a​i​ x​0​ + ∑ a​k+i​ x​k
k=1

n−i
= ∑ a​k+i​ x​k​ --(1)
k=0

Termination:
The following loop eqn (1) will terminate when i=0
n
Therefore, y = ∑ a​k​ x​k
k=0
d)
The given code fragment correctly evaluates a polynomial characterized by the
coefficients as the invariant of the loop is a sum which equals a polynomial with the
given coefficients.

Ans 7)

Θ has a special property that it is symmetrical as it is by definition average case .


klnk = Θ (n)
Also means that n= Θ (klnk) __(1)

Now take ln on both sides:


ln(n) = Θ (ln(klnk))
ln(n) = Θ (ln(k) + ln(lnk)) = Θ (ln(k)) __(2)

Divide equation (1) and (2) :


n Θ(klnk) klnk
ln n = Θ(ln(k))
= Θ ( ln(k) ) = Θ (k)

n
Therefore, ln n = Θ (k)

Ans 8)
a) In order to show this, ​when k >= d, we have to show there exists constants c,n​0 >
​ 0
k​
such that 0 <= p(n) <= c * (n​ ) for all n>=n​0

p(n) = a​0​ + a​1​n​1​ + 2​ d​


​ a​2​n​ ​ + . . . . .+a​d​n​ ​ ---(1)

Now as k >= d, for all possible values of i, (i−k) <= 0, which implies that all n​i-k​ <= 1 for all
d
n >= 1. There we can say that p(n) <= ∑ a​k​ by equation (1).
k=0
d
Hence we can say that 0 <= p(n) <= c * (n​k​) where c = ∑ a​k​ and n​0 =
​ 1.
k=0
k​
Hence p(n)=O(n​ ).

b) In order to show this, ​when k <= d, we have to show there exists constants c , n​0 >
​ 0
k​
such that 0 <= p(n) <= c * (n​ ) for all n>=n​0

p(n) = a​0​ + a​1​n​1​ + 2​ d​


​ a​2​n​ ​ + . . . . .+a​d​n​ ​ ---(1)

Now as k <= d, p(n) >= a​k​n​k


Hence we can say that 0 <= c * (n​k​) <= p(n) where c = a​k​ and n​0 =
​ 1.
k​
Hence p(n)= Ω (n​ )

c) In part (a) and (b), we proved that when k=d, p(n)=O(n​k​) and p(n)= Ω (n​k​) respectively.
Hence we can also say that p(n)= Θ (n​k​)

d) Small-o notation gives tighter bound to Big-O notation.


See the proof of inequality (a). We simply need to remove inequality there. From there
we find:
p(n) = a​0​ + a​1​n​1​ ​+ a​2​n​2​ ​ + . . . . .+a​d​n​d​ ​ ---(1)

Now as k > d, for all possible values of i, (i−k) < 0, which implies that all n​i-k​ < 1 for all
d
n >= 1. There we can say that p(n) < ∑ a​k​ by equation (1).
k=0
d
Hence we can say that 0 <= p(n) < c * (n​k​) where c = ∑ a​k​ and n​0 =
​ 1.
k=0
Hence p(n) = o(n​k​).

e) Small- ω notation gives tighter bound to Big- Ω notation.

See the proof of inequality (b). We simply need to remove inequality there. From there
we find:
p(n) = a​0​ + a​1​n​1​ + 2​ d​
​ a​2​n​ ​ + . . . . .+a​d​n​ ​ ---(1)

Now as k <= d, p(n) >= a​k​n​k

Hence we can say that 0 <= c * (n​k​) < p(n) where c = a​k​ and n​0 =
​ 1.

Hence p(n)= ω (n​k​).

You might also like