The problem
Koko loves to eat bananas. There are n
piles of bananas, the ith
pile has piles[i]
bananas. The guards have gone and will come back in h
hours.
Koko can decide her bananas-per-hour eating speed of k
. Each hour, she chooses some pile of bananas and eats k
bananas from that pile. If the pile has less than k
bananas, she eats all of them instead and will not eat any more bananas during this hour.
Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.
Return the minimum integer k
such that she can eat all the bananas within h
hours.
Examples
Input: piles = [3,6,7,11], h = 8
Output: 4
Input: piles = [30,11,23,4,20], h = 5
Output: 30
Input: piles = [30,11,23,4,20], h = 6
Output: 23
Constraints
- 1 <= piles.length <= 10^4
- piles.length <= h <= 10^9
- 1 <= piles[i] <= 10^9
Explanation
From the description of the problem we know that we have n
piles of bananas given to us in the input array piles[i]
.
We are also given the second parameter h
, which is the number of hours that we have in order to eat all of the bananas.
Koko has an eating speed at which she can eat a certain amount of bananas per hour, and that variable is k
, where k
is the value that we are trying to determine as the solution to this problem.
We also learn that Koko can only eat one
entire pile of bananas in one hour.
Brute Force Solution
func minEatingSpeed(_ piles: [Int], _ h: Int) -> Int {
var speed = 1
while true {
var totalTime = 0
for pile in piles {
totalTime += Int(ceil(Double(pile) / Double(speed)))
}
if totalTime <= h {
return speed
}
speed += 1
}
return speed
}
Explanation
Let’s look at the first example and try to figure out the way we can solve this problem.
The brute force way is to start from k = 1
.
This way Koko can only eat 3 / 1 = 3
, plus 6 / 1 = 6
, that will be 9
and it’s more than h = 8
, so this way Koko can only eat one
pile.
We know that the minimum k
value can only be 1
because that would mean that Koko is barely eating any piles.
As for the maximum value for k
, it will be the maximum value in our input array.
To solve this problem, we are going to try to iterate over k
in the range 1 … max(piles)
, and we will continue until we find our value that allows us to eat every single pile in less than or equal to our h
value.
The time complexity for this solution will be O(m*n).
But why should we iterate over every single element in the k
range when we have our target h
, and we can apply binary search algorithm and optimize our solution?
Time/ Space complexity
- Time complexity: O(m*n)
- Space complexity: O(1)
- where
m
is the length of the input array andn
is the maximum number of bananas in a pile.
Binary Search Solution
func minEatingSpeed(_ piles: [Int], _ h: Int) -> Int {
var l = 1
var r = piles.max()!
var res = r
while l <= r {
let m = (r + l) / 2
var hours = 0
for p in piles {
hours += Int(ceil(Double(p) / Double(m)))
}
if hours <= h {
res = min(res, m)
r = m - 1
} else {
l = m + 1
}
}
return res
}
Explanation
From the solution above we learn that we can apply the binary search algorithm and reduce time complexity to O(logm * n)
.
We know that the potential rate k
that Koko eats bananas is going to be in the range from 1
to max(piles)
(in our example it’s 11
).
- Next, we are going to have the
left
pointer at the start and theright
pointer at the end of the range. - Next, we compute the middle pointer, and our
k
. So for middle value6
, our rate of eating bananas will be6
and ourres
value will be6
. We are not going to stop because we are looking for the minimumk
value. - Now, we can discard all elements on the right side, and only look at the left side. Our middle pointer will be at value
3
, and the rate of eating bananas will be3/3 + 6/3 + 7/3 + 11/3 = 10
. The rate is greater than ourh
, so we are going to update ourleft
and middle pointers. - Next, we repeat the steps we did before and calculate the rate that will result in value
8
. So at this point our middle pointer is at4
, and our result is6
, so we can update it to4
. - Lastly, we are going to stop our binary search and return the result because if we continue, we will be searching values that we already crossed out.
Time/ Space complexity
- Time complexity: O(log(m * n))
- Space complexity: O(1)