I went for an interview, and got a workload problem:
Problem: write a function to tell whether a series of workloads will exceed
the maximum workload or not
Input: MaxWorkLoad: example 10
Timeslot and workload: example [(2, 6, 3), (3, 8, 2), ... ]
The (2, 6, 3) is begin time, end time, and workload
And it means from time 2 to time 6, the workload is 3
You can treat the 2, 6 as the UNIX epoch time.
The time may not be integers, so instead of 2, it can be 2.2
The input can be in any time order. For example: [(20, 60, 3), (3, 8, 2)]
The workload will "add up", so a 3 and 2 will add up to 5
Output: a boolean indicating whether the series of workload can fit in without
exceeding MaxWorkLoad
The short question is: does this workload problem belong to a class of algorithm, and that when the array is empty, but data keep on coming in for M
times and we need to tell possible or not, for M
times, is there a better solution than O(M * M)
?
Details:
If I focused on how to determine whether the time ranges will overlap with each other, it turns out it is not an easy solution.
So I am not sure whether this is suitable as an interview question, as you may either know how to solve it or you don't. If you have seen it before, you will solve it like a breeze. If you haven't seen it before, I don't think 20 minutes may be enough time for you to get unstuck.
You may want to think about how you may solve it, if you want to have some fun.
The simple solution, which I could come up with, but after 15 minutes later, actually, can be: simply use a dictionary, and use the time boundary as the key, and if it is (2, 6, 3)
, then just mark it as dict[2] = 3
and dict[6] = -3
.
Likewise, for (3, 8, 2)
, then dict[3] = 2
and dict[8] = -2
(and actually, if we treat the time endpoint as inclusive, then we won't have dict[8] = -2
but have dict[9] = -2
, treating it as dropping some workload at time 9
instead of at 8
)
And then, once you have the whole dictionary, now loop through each key in the dictionary, in sorted order, and keep a CurrentWorkLoad
number as the work load. So when you see dict[2]
as 3
, add 3
to CurrentWorkLoad
, and when you see dict[3]
, add the 2
to CurrentWorkLoad
, and when you see dict[6]
, add the -3
to CurrentWorkLoad
.
So as soon as CurrentWorkLoad
is greater than MaxWorkLoad
, then you can return false
right away. Otherwise, at the end of the loop, simply return true
.
And what if there is (2, 6, 3)
and (6, 8, 1)
, meaning that the endpoint can "overlap" at the time 6
? So I came up with, either use an array to remember all the values when it collides at 6
, or, simply add up the values. So the first time you see (2, 6, 3)
, then dict[6] is -3
, and when you see (6, 8, 1)
, then dict[6] += 1
and becomes -2
.
So if in JavaScript, it is like
dict[beginTime] ||= 0; // if not defined, then set it to 0
dict[beginTime] += workload;
dict[endTime] ||= 0;
dict[endTime] -= workload;
and the rest of the algorithm will stay the same.
So the time complexity for the array size N
is O(N log N)
, because we need to sort the keys.
The interviewer then asked me, what if this operation is repeated M
times?
So for example, if the initial array is empty, but data keep on coming in, for M
times, and M
can be a million or ten million. Then what is the time complexity? I initially said then it is O(M * M log M)
, but later on found out it could be O(M * M)
, because we don't need to sort the keys every time. We can just "insert" the key in an already sorted list.
Is there a class of algorithm or problem solving that is related to this and have a solution better than O(M * M)
?