Throwing eggs from the rooftop
Daily Coding Problem 24
Welcome back with another problem to solve! Today we are dealing with eggs falling from rooftops with this really nice problem, which will involve two possible solutions: one pretty naive and a more cleaver one. This last one will also give us the chance to talk about a quite famous algorithm.
As always, today’s problem is provided by the wonderful newsletter Daily Coding Problem, which you can subscribe for free to get your daily coding challenge too. Check it out and try to solve your problems too!
Enough talking then, let’s see the problem!
The problem
This problem was asked by Goldman Sachs in a job interview. Let’s see the problem.
You are given
N
identical eggs and access to a building withk
floors. Your task is to find the lowest floor that will cause an egg to break, if dropped from that floor. Once an egg breaks, it cannot be dropped again. If an egg breaks when dropped from thexth
floor, you can assume it will also break when dropped from any floor greater thanx
.Write an algorithm that finds the minimum number of trial drops it will take, in the worst case, to identify this floor.
For example, if
N = 1
andk = 5
, we will need to try dropping the egg at every floor, beginning with the first, until we reach the fifth floor, so our solution will be5
.
So, we are given some eggs to throw from different floors of a building. We are sad that from a certain floor (which we will call targetFloor
) from which eggs thrown out do not break when falling to the ground. From that floor to every floor below it, the eggs won’t break when thrown out from the window. What we are asked to do is to find an efficient method to find the targetFloor
.
As anticipated, we’ll see two methods to solve this: a really simple one, which will brute force the solution out, but it will not be efficient. The second one will be much more efficient, and will try to solve the problem breaking the least number of steps. It will also give us the chance to talk about a really famous and important algorithm, one of those you need to know to do … basically anything!
Setting up the environment
To start off, we need to set up a bit of environment, namely the building and the targetFloor
. To create the building, we simply create an array containing the numbers of the floors, from the ground floor to the nᵗʰ floor. Then we generate a random number which will be our targetFloor
. We’ll write this problem in Go once again: simply enough to be readable, but complex enough to understand the inner mechanics.
We first create the array which will serve as our building: we can give it the size we want, the greater the size the highest the building will be. After that we create an instance of the targetFlor
using the math/rand
module built in Go. Basically, we create a new random integer between 0 and the height of the building (… the length of the array :D) using as source the current time.
The brute force solution
Of course the simplest solution possible would be to throw each egg on each floor out, so to see on which floor the eggs start to break. Since we have a variable containing that information, one could simply do a for loop to solve the problem:
While being this the most simple solution, it is unfortunately highly inefficient. Imagine if the right floor is the top one: one must break 100.000 eggs to solve the problem: that would be a huge omelette but quite a waste! Generally speaking, this solution has a time complexity of O(n) because the complexity of the solution grows linearly to the complexity of the input problem. This is not the most efficient solution we could think of though.
An efficient solution
Let’s think about an efficient solution then. Instead of walking floor by floor breaking each egg on each floor, we could take a guess and, based on the result of that guess, adjusting the next guess. Here’s an example: suppose we have a building with 10 floors and the targetFloor
is floor 7 (we don’t know that, of course). We could take the following guesses:
Basically, we guess that the targetFloor
is the middle floor of the building. We throw the egg from there and the possible outcomes are two:
- the egg breaks, meaning that we are too high. We can discard floor higher than this one, included, and keep going on with our guesses.
- the egg does not break, meaning that we are too low or at the correct floor. We discard every floor lower than this one, included, and
Given this, we now take another educated guess towards the middle floor or the “remaining” building and apply the same strategy seen above. We can go on with this approach until we are left with one floor.
If you happen to recognize this approach, you are perfectly right: this is simply binary search applied to a “real world” problem. Binary search is a simple and neat divide and conquer algorithm, meaning that at each step the size of the problem gets halved until we find the solution. This means that this algorithm, compared to the previous one, is way faster. Let’s see the code!
Let’s take a deeper look. The binary search function takes in 4 arguments:
overArray
, an array of integers, which is the building we are looping over;bottom
, the bottom index of the building;top
, the top floor index of the building;breakFloor
, the variable holdingtargetFloor
to check if we can find it in the building.
After that, we loop over the building while bottom
is lower than top
: in binary search, when the two positional arguments interlace and swap, it means that the searched element was not found. Therefore, if the algorithm ends up in this situation, the loop ends and we return -1
, meaning that the element we are looking for was not present in the array. If we are still searching the element, we apply what shawn in the image above. We calculate the middlePoint
element as the floor between bottom
and top
and we check if middlePoint == breakFloor
. If it is, we return the middlePoint
as result. If it’s not, we adjust bottom
or top
accordingly: if middlePoint
is greater that breakFloor
, it means we are too high on the building so we lower our prediction by setting the top
possible floor to middlePoint — 1
. If middlePoint
is smaller than breakFloor
, we adjust our bottom
by setting is as middlePoint+1
.
Now to check everything, in the main
function we generate the environment as before and create a new variable called bsFloor
which will hold our result. To confirm that our algorithm brought us to the right result, we print out both bsFloor
and targetFloor
, which was previously generated randomly.
Time complexity
As we anticipated before, this algorithm is way faster than the linear one. Since we halve the building at each step, we can find the correct floor in log₂(n) where n is equal to len(building)
. This means that the time complexity of this algorithm is O(log(n)). To give you some comparison between the linear solution and this last one, if the building has 100 floors the linear algorithm takes in the worst case 100 iterations, while the binary search algorithm takes log₂100 = 6.64, so 7 iterations. Also, this last one is increasinlgy more efficient than the linear one, because the more the building grows the more the binary search is efficient. For a building with 1.000.000.000 floors, the linear one takes 1.000.000.000 steps, while the binary one takes log₂1.000.000.000 = 29.9, so 30 steps. A huge improvement!
Conclusion
This is it! I hope you enjoyed the article as much I had fun trying to solve the challenge! If so, please leave a clap or two, it would be a great support! If you like these type of articles and want to see more, follow the page as I release this type of content every time I can. Finally, if found this article interesting or helpful and would like to contribute offering a coffee, feel free to do son on my Ko-fi page!
And, as always, thanks for reading!
Nicola