You are on page 1of 12

Mid-Semester Exam Solution

Question 1)
Rubric: (5 marks total)
● 3 marks for program and time complexity
○ 2 marks if brute force approach is correctly implemented with proper
time complexity (or)
○ 3 marks if stack based approach is correctly implemented with proper
time complexity
● 2 marks for executing the algorithm on the example and arriving at the correct
answer(with proper explanation)

Explanation:
The key idea to solve this problem is to understand that water can only be present if there
exists a block of greater height, both on the left and the right side than the current
block.Then the amount of water a block can hold(above it) is equal to the minimum of the
maximum height present on both the left and right half minus the height of the current block.

Bruteforce Approach:
Since the task is to find the maximum height on left and right for each element of the array,
simply traverse each element of the array A. For each element, find the maximum height on
the left and maximum height on the right. Find the volume of water stored on top of this block
by computing min(right_max, left_max) – A[i] and add it to the answer. Below is the
step-wise explanation:
● Initialise a variable res to 0, to store the final answer.
● Traverse the array A and for each element:
○ Initialise left_max = 0 and right_max = 0
○ Traverse from A[i] till the beginning and update:
■ left_max = max(left_max, A[i])
○ Similarly, traverse from A[i] till the end of the array and update:
■ right_max = max(right_max, A[i])
○ Add min(left_max, right_max) – A[i] to res.
Time Complexity: O(N2)

Implementation using stacks:


The idea is to keep track of the area between the current block A[i] and all the previous
blocks with smaller heights in the array. We can simply use a stack to track the index of the
previous smaller blocks. Below is the step-wise explanation:

● Declare a stack.
● Traverse the array A from left to right:
○ If the current block A[i] is larger than the top of the stack A[stack[-1]], then the
block at the top of the stack is confined between the current block and the
previous block in the stack. If this condition is satisfied, we perform the
following operations :
■ Perform stack.pop(), store the value in a variable named top as
indicated in line 11.
■ Add the water that can be stored.The total volume of water can be
calculated as follows (as seen in lines 13 to 18 in code):
● Length of water stored = i – stack[-1] – 1, where i is the current
index and stack[-1] is the top element in stack
● Height of left block = A[stack[-1]], height of right block = A[i],
Height of water stored = min(left,right) – A[top]
● Volume = length X height X width where width = 1 as given in
question
● Add the volume to res.

Time Complexity: O(N)


Demo on given example ⇒

A = [6,5,4,2,3,4,7,3,4,6,3,5]

Total volume of water stored : 19


Question 2) [3 marks total]
Rubric: Part i = 0.5 marks ; Part ii = 1.5 marks ; Part iii = 1 mark
Question 2) Part i)

NOTE: Other 3-ary Min-Heaps which are complete can also be valid solutions.
Part ii) METHOD 1 ⇒

NOTE: “return (i-1)/3” directly will work too.


METHOD 2 ⇒

Part iii)
METHOD 1 ⇒

1. Given i = 2031
2. Since 2031 ≠ 0
3. int j = (2031-1) / 3 = 676
4. 676 returned.

METHOD 2 ⇒

1. Given i = 2031
2. Since 2031 ≠ 0
3. 2031%3 = 0
4. First 2 if conditions fail
5. j = (2031-3)/3 = 676
6. 676 returned.

Question 3)

Rubric: (3 marks total)


● 1.5 marks for Part (i) - For listing all the conditions
● 1.5 marks for Part (ii) - Any valid example will suffice

i) Huffman code is a coding scheme that builds a binary tree from leaves up - takes the two
symbols having the least probabilities, assigns them equal lengths, merges them, and then
reiterates the entire process. Please find below conditions on the probabilities:

● Pa + Pb + Pc + Pd = 1.
● Initially among (Pa , Pb , Pc , Pd), Pa and Pb should be the least. These two smallest
probabilities are combined to form a new internal node, and this internal node must
have a probability equal to the sum of the two probabilities Pa + Pb.
● Next among {Pa + Pb, Pc, Pd}, Pa + Pb and Pc should be the least.
● Following this logic, we can conclude Pd must equal maximum of all probabilities. Pa
and Pb are the two least probabilities.

Please find below inequalities that must be satisfied :


● Pa <= Pc , Pa <= Pd
● Pb <= Pc , Pb <= Pd
● Pc <= Pd, Pa+Pb <=Pc, Pa+Pb <=Pd

ii) An example solution to these conditions where only the tree T is obtained could be:
● Pa = 0.1
● Pb = 0.2
● Pc = 0.3
● Pd = 0.4
In this case, the two smallest probabilities, Pa and Pb, are combined to form a new internal
node with probability 0.3. The new internal node is then added to the set of symbols, and the
process is repeated with the probabilities 0.3, Pc, and Pd to obtain the complete tree T. No
other tree can be obtained with these probabilities.

Question 4) [5 marks total]


Rubric: 3 marks for correct function code/pseudocode + 2 marks for correct execution
on given example

(Part 1) function code/pseudocode

Function Q=insert(T,w)

n=T.nos; found=0; m=len(w);


If m==0
return;
end;
for i=1:n
k=match(w,T.string[i])
If k>0
found=1;
If k==len(T.string[i])
{
w=w(k+1:m)
Q=insert(T.child[i],w);
}
Else
Insert 2 nodes
end;
end;
If found==0
insert 1 node;
end;

Endfunction

NOTE: For more details, refer to slide 6 of Tutorial 6 + Next week

(Part 2) Execute the algorithm for the tree T below and the string w=baba
Recursion 1: ( != represents INEQUALITY)
T = root, w = “baba”, n = 2, found = 0, m = 4
m != 0
for i = 1 (since 1 to n=2)
k = match(baba , b) ⇒ k=1 > 0
found = 1
k = 1 == 1
w = w(1+1:4) = “aba”
Q = insert(root.child[1], aba)

Recursion 2:
T = root.child[1], w = “aba”, n = 2, found = 0, m = 3
m != 0
for i = 1 (since 1 to n=2)
k = match(aba , cba) ⇒ k=0 < 0
for i = 2
k = match(aba , aca) ⇒ k=1 > 0
found = 1
k = 1 != 3
Insert 2 nodes

Finally obtained trie shown above (Full marks if dry run correct)
Question 5) Rubric : [6 marks] Part i = 3 marks ;
Part ii = if version 1 used for (b) = 1 mark
if version 2 used for (b) = 2 marks ;
Part iii = 1 mark

PART (i) Data structure :


FOR TT ⇒ TT = A vector of struct objects where struct are defined as follows (total k trips):
Struct Trip{
TID; \\ Ti : trip id
ts; \\ start time
tr; \\ end time
destinations[]; \\ array of destinations
}
Where TT is sorted by start time (ts).

⇒ Operations (standard operations of vectors): “insert, delete, access at a given index” of


structure objects.

FOR S ⇒ S = a list/hashtable with all the Destination id as elements, where S[i] = Di+1 ,
where each element of the list is a list of trip IDs (TID).

⇒ Operations (standard operations of lists): “insert, delete, access at a given index” where
links are added at each element to add TIDs.

PART (ii) Operations implementation : {m = total destinations, k = total trips}


(a) Insert trip =
○ In TT = Find the appropriate location for the given trip by applying binary
search on TT based on starting time and insert it after shifting other trips
[O(log k) + O(k) // search + shifting]
○ In S = For all destinations visited in the inserted trip, if it is already in S, add a
link to the list in the end. If not, add an element to S. [O(m)]
Delete trip =
● In TT = Traverse TT and delete the structure with given TID and delete the
structure. Shift other structures [O(k)] (NOTE: can’t apply binary search here
as not sorted by TID)
● In S = As we know the TID of trip to be deleted, so we know destinations it
visits. Traverse S and delete Trip with that TID from those destinations.
[O(k*m)]
Modify trip =
○ In TT = Traverse TT and modify the structure with given TID. (Note: Shift if
start time changed) [O(k)] (NOTE: can’t apply binary search here as not
sorted by TID)
○ In S = If new destinations are added to the trip, traverse SS and add that TID
to those destinations. [O(1)] If some destinations are removed, traverse SS
and remove TID from those destinations [O(k)]
(b) Version 1⇒ given a time t, list all the trips which are in motion at that time =
For a given time t, Traverse the vector TT till start time of accessed element is <= t
and for each element check if Trip.ts < t and t < Trip.tr. If true, then add that trip to list
of active trips. [O(k)]

Version 2 ⇒ Make another data structure “Q” which is a BST of 2K nodes (sorting
parameter = time), where each node is a list or a set, representing currently active
trips (Trip IDs) at that time stamp. Every time a trip begins or ends (total 2K events),
a new node is added with the updated set/list (if a trip begins, add that Trip ID to the
set; if a trip ends, remove that Trip ID from the set)
⇒ For a given time t, the BST can be traversed to reach the set representing
currently active trips.
● Time complexity = O(H) {H=height of BST, H = log(2K) = log(K) in
average case}
Note : For insertion, deletion and modification of trips (operations in (a)), just
reach the node with time equal to ts/tr of that trip and add/delete the trip id in
the node’s set, just like normal BST add/delete operation.
● Time complexity =
○ Insertion = O(H) {H=height of BST, H = log(2K) = log(K) in average
case}, since O(1) time to insert in that set/list
○ Deletion/Modification = O(H*K) {H=height of BST, H = log(2K) =
log(K) in average case}, since the set has to be traversed and
other trips shifted to delete/modify the needed Trip ID and size of
set in worst case = K

(c) Given a destination Di, list the trips which visit this destination. = Since ordered
by Di in S, directly access Di and a list of all trips is obtained. [O(1)]

PART (iii) Worst case Time complexity of each operation is mentioned above with the
operation.

NOTE ⇒ Other solutions are also possible and will be awarded marks if as efficient as
above solution.

Question 6)

Rubric: (8 marks total)


● 1 mark for part (i) : 0.5 for installation of a token dispenser system to dispense
tokens to customers upon their arrival + 0.5 for type of operation (either 'a' for
cheque encashment or 'b' for passbook printing, or 'ab' for both)
● 3 marks for Part (ii) : 1 mark for using two queues Q1 and Q2 as stated in
solution + 1.5 marks for listing the correct operations + 0.5 mark for the places
of operation
● 1 mark for Part (iii) : 0.5 for stating use of pop/head operation at each counter +
handling of conflicting cases that may arise for customers with ‘ab’ token
● 1 mark for Part (iv) : 0.5 for taking token from token dispensing machine upon
arrival and waiting in the queue for one’s turn + 0.5 for specific instruction for
to customers with ‘ab’ token as stated in solution
● 2 marks for Part (v) : 1 mark for valid assumptions + 1 mark for undisciplined
behaviours

(i) The bank premises will need to have a token dispenser system installed which will
dispense tokens to customers upon their arrival. The tokens will indicate the type of
operation required (either 'a' for cheque encashment or 'b' for passbook printing, or 'ab' for
both). The counters will be labelled clearly to indicate which operations they can perform.The
bank will also need to install displays that show the current ticket number being served at
each counter.

ii) Consider two queues, Q1 and Q2, for customers who have tokens 'a' and 'ab' and
customers who have tokens 'b' and 'ab', respectively.

The operations allowed are:

● enqueue(token_number, services): Adds a token with a unique token_number to the


queue. The services parameter specifies the type of service requested (either 'a' for
cheque encashment or 'b' for passbook printing, or 'ab' for both).
● pop(): The customer at the head of a queue is popped from the queue and is the next
one to be served.
● size(): Returns the current size of the queue.
● head() : returns the token number of the head of the queue without popping it.
● delete(token_number) : deletes the token_number passed as argument
● is_present(token_number) : returns True if a token_number is present in a queue
else False
● is_empty(): Returns True if the queue is empty, else False.
● Both Q1 and Q2 operate through these operations.

List of locations where these operations will be executed :

● Customers with token 'a' will be present only in Q1 and should be called to counter A
once their turn comes up.
● Customers with token 'b' will be present only in Q2 and should be called to counter B
once their turn comes up.
● A customer with an 'ab' token can be present in both the queues and will be served
either entirely at A or first at B partly and then at A.

(iii) A uses Q1.pop() and B uses Q2.pop() and serves the customers according to their needs.
note that a customer who has an ‘ab’ token may be popped at counter A with her ‘b’ part satisfied
earlier.

Since the processing time for 'a' is 10 minutes and for 'b' is 3 minutes, the order can be
enforced for customers with 'ab' tokens.There are two possible cases that need to be
handled. We use Q1.head() and Q2.head() for the same.

● Customer with 'ab' token present at the head of both queues Q1 and Q2 :The
customer should not be called to counter B where only service 'b' is available. The
customer should directly be sent to counter A i.e. if Q1.head() = Q2.head(), then we
perform token_num = Q1.pop() and send the customer to counter A. Then perform
Q2.delete(token_num) to remove the customer from Q2.
● Customer is present at the head of Q2 but not present at the head in Q1: Note
the minimum time required for a customer to be served at counter A is 10 mins.
Since the customer is present at the head of Q2, he will be served next at counter B.
But his turn is yet to come up in Q1. The customer should be called to counter B and
his service request for 'b' would be completed in 3 mins. Now for the remaining
service ‘a’, he has to wait for his turn to come up in Q1, where he would be called to
counter A and would only be offered service 'a'. This would reduce the overall waiting
and service time for the customer. The sequence of operations would be : Check if
Q1.is_present(Q2.head()) then Q2.pop() and send the customer to counter B.

(iv) The instructions to customers should be as follows:

● Take a token from the token dispensing machine depending on the service required
(either 'a' for cheque encashment or 'b' for passbook printing, or 'ab' for both).
● Wait in the waiting area until your token number and counter number are displayed
on the display board.
● If you desire service “ab” then you may either be called at (i) counter B followed by
counter A or (ii) just at counter A. In case of (i), indicate to the person at counter A
that your passbook printing has already been done.
● Proceed to the designated counter and present your cheque or passbook for the
requested service.

(v) Assumptions:

● There will be no system failures or malfunctions.


● The officers at the counters will follow the procedure as outlined in (iii).
● All customers will follow the ticket system and take the appropriate ticket for their
required operation.

Two undisciplined behaviours that are not taken care of by the system are:

● Customers taking 2 tokens by mistake. Then counters A and B have to wait for 30
seconds and pop Q1 or Q2 again.
● Customers taking two separate tokens ‘a’ and ‘b’ instead of a single token ‘ab’- This
could lead to clashes. The customer could end up missing his turn for 'a', if his turn
for 'a' comes up while he is getting served for 'b'.

For more details,please refer to Priority Queues.pptx .

You might also like