We're finding the minimum speed to reach the office on time. Let's start from speed 1, and check if it's possible to reach the office within hour hours. If not, we increase the speed by 1 and check again.
speed = distance / time
time = distance / speed
s = 1
[1, 3, 2]
ceil(1/1) + ceil(3/1) + 2/1 = 6 <= 6
s = 2
ceil(1/2) + ceil(3/2) + 2/2 = 1 + 2 + 1 = 4
s = 3
ceil(1/3) + ceil(3/3) + 2/3 = 1 + 1 + 0.66 = 2.66 <= 6fun minSpeedOnTime(dist: IntArray, hour: Double): Int {
var speed = 1
while (speed <= 10000000) {
// See below for the implementation of getTotalHours()
if (getTotalHours(dist, speed) <= hour) return speed
speed++
}
return -1
}We can optimize the linear search solution with some modifications based on some key observations:
- The minimum speed is
1, and the maximum speed is the maximum of possible value, which is10^7(based on the problem constraints). - As we increase the speed, the time to reach the office is shorter, and vice versa. This exhibits the monotonicity characteristic, so we can use binary search to find the minimum speed: We're looking for the first element that satisfies the condition:
getTotalHours(dist, middle) <= hour.
It's a little bit confused why we don't ceil the last distance, maybe just skip it.
fun minSpeedOnTime(dist: IntArray, hour: Double): Int {
val min = 1
val max = 10000000
var left = min
var right = max
while (left <= right) {
val middle = left + (right - left) / 2
val isValid = getTotalHours(dist, middle) <= hour
// Find the first element that meets the condition (can reach the office)
if (isValid) {
right = middle - 1
} else {
left = middle + 1
}
}
// We check if the left is in the range, if not, return -1
return if (left in min..max) left else -1
// Or
// return if (left > max) -1 else left
}
// We calculate the total hours to reach the office with the given speed.
// ceil(dist[0] / speed) + ceil(dist[1] / speed) + ... + ceil(dist[n - 2] / speed) + dist[n - 1] / speed
// The last distance doesn't need to wait, so we don't need to ceil it.
private fun getTotalHours(dist: IntArray, speed: Int): Double {
var hours = 0.0
// We iterate all distances except the last one: because we have to wait if the hour is not an integer.
for (d in 0 until dist.size - 1) {
hours += Math.ceil(dist[d].toDouble() / speed) // If the hour is 1.5, then total hours is 2.
}
// We add the last distance to the total hours, which we don't have to wait.
hours += dist[dist.size - 1].toDouble() / speed
return hours
}- Time Complexity:
O(n * log m), wherenis the size of thedistandmis the maximum speed. - Space Complexity:
O(1).