Minimum Skips to Arrive at Meeting On Time
HardPrompt
You are given an integer hoursBefore, the number of hours you have to travel to your meeting. To arrive at your meeting, you have to travel through n roads. The road lengths are given as an integer array dist of length n, where dist[i] describes the length of the ith road in kilometers. In addition, you are given an integer speed, which is the speed (in km/h) you will travel at.
After you travel road i, you must rest and wait for the next integer hour before you can begin traveling on the next road. Note that you do not have to rest after traveling the last road because you are already at the meeting.
- For example, if traveling a road takes
1.4hours, you must wait until the2hour mark before traveling the next road. If traveling a road takes exactly2hours, you do not need to wait.
However, you are allowed to skip some rests to be able to arrive on time, meaning you do not need to wait for the next integer hour. Note that this means you may finish traveling future roads at different hour marks.
- For example, suppose traveling the first road takes
1.4hours and traveling the second road takes0.6hours. Skipping the rest after the first road will mean you finish traveling the second road right at the2hour mark, letting you start traveling the third road immediately.
Return the minimum number of skips required to arrive at the meeting on time, or -1 if it is impossible.
Example 1:
Input: dist = [1,3,2], speed = 4, hoursBefore = 2
Output: 1
Explanation:
Without skipping any rests, you will arrive in (1/4 + 3/4) + (3/4 + 1/4) + (2/4) = 2.5 hours.
You can skip the first rest to arrive in ((1/4 + 0) + (3/4 + 0)) + (2/4) = 1.5 hours.
Note that the second rest is shortened because you finish traveling the second road at an integer hour due to skipping the first rest.Example 2:
Input: dist = [7,3,5,5], speed = 2, hoursBefore = 10
Output: 2
Explanation:
Without skipping any rests, you will arrive in (7/2 + 1/2) + (3/2 + 1/2) + (5/2 + 1/2) + (5/2) = 11.5 hours.
You can skip the first and third rest to arrive in ((7/2 + 0) + (3/2 + 0)) + ((5/2 + 0) + (5/2)) = 10 hours.Example 3:
Input: dist = [7,3,5,5], speed = 1, hoursBefore = 10
Output: -1
Explanation: It is impossible to arrive at the meeting on time even if you skip all the rests.
Constraints:
n == dist.length1 <= n <= 10001 <= dist[i] <= 1051 <= speed <= 1061 <= hoursBefore <= 107
Approaches
2 approaches with complexity analysis and trade-offs.
This problem can be modeled using dynamic programming. We can define a state dp[i][j] that represents the minimum possible arrival time at the start of road i having used exactly j skips. By iterating through each road and considering the two choices at each rest stop (skip or wait), we can build up a solution. The final answer is the minimum j for which the total travel time is within the hoursBefore limit.
Algorithm
- Define a 2D DP array,
dp[i][j], to store the minimum start time for roadiusingjskips. - To avoid floating-point precision issues, we work with 'distance' units (
time * speed) and uselongintegers. So,dp[i][j]will store the minimum start 'distance' for roadiwithjskips. - Initialize
dptable of sizen x nwith a very large value, representing infinity. Setdp[0][0] = 0, as we start at time 0 before the first road with 0 skips. - Iterate from road
i = 0ton-2. For each road, iterate through the possible number of skipsjfrom0toi. - For each state
dp[i][j], calculate the finish 'distance' after traveling roadi:finish_dist = dp[i][j] + dist[i]. - From this
finish_dist, determine the two possible start 'distances' for the next roadi+1: a. No skip: The start 'distance' isceil(finish_dist / speed) * speed. This is calculated using integer arithmetic as((finish_dist + speed - 1) / speed) * speed. b. Skip: The start 'distance' is simplyfinish_dist. - Update the
dptable for roadi+1:dp[i+1][j] = min(dp[i+1][j], no_skip_start_dist)dp[i+1][j+1] = min(dp[i+1][j+1], skip_start_dist)
- After filling the
dptable, iterate through the number of skipsjfrom0ton-1. - For each
j, calculate the final arrival 'distance' after the last road:total_dist = dp[n-1][j] + dist[n-1]. - If
total_distis less than or equal tohoursBefore * speed, thenjis a possible number of skips. The first suchjwe find is the minimum required, so we return it. - If the loop completes without finding a solution, it's impossible to arrive on time. Return -1.
Walkthrough
We use a 2D array, dp[i][j], where i is the road index (from 0 to n-1) and j is the number of skips used (from 0 to i). To avoid floating-point precision errors, we can work with integer 'distances' by multiplying all time values by speed. So, dp[i][j] will store the minimum 'distance' traveled to be ready to start road i, using j skips.
The base case is dp[0][0] = 0, meaning we are at the start of the first road at time 0. We then iterate from road i = 0 to n-2. For each road, we calculate the finish 'distance' and then update the possible start 'distances' for the next road, i+1. If we don't skip the rest, the time is rounded up to the next integer hour, which corresponds to ceil(finish_dist / speed) * speed. If we do skip, the start time for the next road is immediate.
After computing all states up to the start of the last road (dp[n-1]), we can find the total travel 'distance' for each possible number of skips. We then check which is the smallest number of skips j that allows finishing within hoursBefore * speed 'distance' units.
import java.util.Arrays; class Solution { public int minSkips(int[] dist, int speed, int hoursBefore) { int n = dist.length; long[][] dp = new long[n][n]; for (int i = 0; i < n; i++) { Arrays.fill(dp[i], Long.MAX_VALUE); } dp[0][0] = 0; for (int i = 0; i < n - 1; i++) { long travelDist = dist[i]; for (int j = 0; j <= i; j++) { if (dp[i][j] == Long.MAX_VALUE) { continue; } // Option 1: Don't skip the rest after road i long finishDist = dp[i][j] + travelDist; long nextStartNoSkip = (finishDist + speed - 1) / speed * speed; dp[i + 1][j] = Math.min(dp[i + 1][j], nextStartNoSkip); // Option 2: Skip the rest after road i long nextStartSkip = finishDist; if (j + 1 < n) { dp[i + 1][j + 1] = Math.min(dp[i + 1][j + 1], nextStartSkip); } } } long maxAllowedDist = (long) hoursBefore * speed; for (int j = 0; j < n; j++) { if (dp[n - 1][j] != Long.MAX_VALUE) { long totalDist = dp[n - 1][j] + dist[n - 1]; if (totalDist <= maxAllowedDist) { return j; } } } return -1; }}Complexity
Time
O(n^2), where n is the number of roads. We have two nested loops, both iterating up to `n`.
Space
O(n^2), where n is the number of roads. This is for the 2D `dp` table of size `n x n`.
Trade-offs
Pros
The DP state and transitions are logical and directly model the problem.
Using integer arithmetic for 'distance' avoids potential floating-point precision issues, making the solution robust.
Cons
The space complexity of O(n^2) can be high for large
n(up to 1000), potentially leading to memory issues.
This approach is a space-optimized version of the 2D dynamic programming solution. By observing that the calculation for the current road's minimum times only depends on the results from the immediately preceding road, we can reduce the space complexity from O(n^2) to O(n). We maintain only the DP states for the current and next roads, discarding older states that are no longer needed.
Algorithm
- The core logic is the same as the 2D DP approach, but we optimize space.
- Observe that to compute the DP values for road
i+1, we only need the values from roadi. This means we don't need to store the entire 2D table. - We can use two 1D arrays, one for the current road's start times (
dp) and one for the next road's start times (next_dp). - Initialize a 1D array
dpof sizenwithdp[0] = 0and others as infinity. This represents the start 'distances' for road 0. - Iterate from road
i = 0ton-2. In each iteration, create anext_dparray. - Loop through skips
jfrom0toi. Based ondp[j], calculate the two possible start 'distances' for roadi+1(with and without a skip) and updatenext_dp[j]andnext_dp[j+1]accordingly. - After the inner loop, replace
dpwithnext_dpfor the next iteration. - After iterating through all rests, the final
dparray will hold the minimum start 'distances' for the last road (n-1). - The final check for the minimum number of skips is the same as in the previous approach: find the smallest
jsuch thatdp[j] + dist[n-1] <= hoursBefore * speed.
Walkthrough
Instead of a 2D dp table, we use a 1D array, dp, of size n. dp[j] will store the minimum start 'distance' for the current road i using j skips.
We start with dp representing the start times for road 0, which is dp[0] = 0 and infinity for all other j. Then, we iterate from i = 0 to n-2. In each iteration, we compute a next_dp array which will hold the start 'distances' for road i+1. The transition logic is identical to the 2D DP approach. After computing all possible start times for road i+1, we assign next_dp to dp and proceed to the next road.
This way, we only ever store the DP states for two adjacent roads at any time, reducing the space requirement to O(n). The final step of checking the dp array (which now holds start times for the last road) against hoursBefore remains the same.
An initial check can be performed: if the total distance divided by speed (the time taken if all rests are skipped) is greater than hoursBefore, it's impossible to arrive on time. This can handle some edge cases early.
import java.util.Arrays; class Solution { public int minSkips(int[] dist, int speed, int hoursBefore) { int n = dist.length; // An optional initial check for impossibility. long totalDistSum = 0; for (int d : dist) { totalDistSum += d; } if ((double) totalDistSum / speed > hoursBefore) { return -1; } long[] dp = new long[n]; Arrays.fill(dp, Long.MAX_VALUE); dp[0] = 0; for (int i = 0; i < n - 1; i++) { long travelDist = dist[i]; long[] next_dp = new long[n]; Arrays.fill(next_dp, Long.MAX_VALUE); for (int j = 0; j <= i; j++) { if (dp[j] == Long.MAX_VALUE) { continue; } // Option 1: Don't skip the rest after road i long finishDist = dp[j] + travelDist; long nextStartNoSkip = (finishDist + speed - 1) / speed * speed; next_dp[j] = Math.min(next_dp[j], nextStartNoSkip); // Option 2: Skip the rest after road i long nextStartSkip = finishDist; if (j + 1 < n) { next_dp[j + 1] = Math.min(next_dp[j + 1], nextStartSkip); } } dp = next_dp; } long maxAllowedDist = (long) hoursBefore * speed; for (int j = 0; j < n; j++) { if (dp[j] != Long.MAX_VALUE) { long totalDist = dp[j] + dist[n - 1]; if (totalDist <= maxAllowedDist) { return j; } } } return -1; }}Complexity
Time
O(n^2), where n is the number of roads. The nested loops structure remains the same as the 2D DP approach.
Space
O(n), where n is the number of roads. We use two 1D arrays of size `n` to store DP states for the current and next roads.
Trade-offs
Pros
Significantly more memory-efficient than the 2D DP approach, making it feasible for larger constraints on
n.Maintains the same O(n^2) time complexity, which is efficient enough for the given constraints.
Cons
The time complexity remains O(n^2), so it's not faster for very large
n.
Solutions
Solution
class Solution {public int minSkips(int[] dist, int speed, int hoursBefore) { int n = dist.length; double[][] f = new double[n + 1][n + 1]; for (int i = 0; i <= n; i++) { Arrays.fill(f[i], 1 e20); } f[0][0] = 0; double eps = 1 e - 8; for (int i = 1; i <= n; ++i) { for (int j = 0; j <= i; ++j) { if (j < i) { f[i][j] = Math.min(f[i][j], Math.ceil(f[i - 1][j]) + 1.0 * dist[i - 1] / speed - eps); } if (j > 0) { f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + 1.0 * dist[i - 1] / speed); } } } for (int j = 0; j <= n; ++j) { if (f[n][j] <= hoursBefore + eps) { return j; } } return -1; }}class Solution {public: int minSkips(vector<int> &dist, int speed, int hoursBefore) { int n = dist.size(); vector<vector<double>> f(n + 1, vector<double>(n + 1, 1e20)); f[0][0] = 0; double eps = 1e-8; for (int i = 1; i <= n; ++i) { for (int j = 0; j <= i; ++j) { if (j < i) { f[i][j] = min(f[i][j], ceil(f[i - 1][j] + dist[i - 1] * 1.0 / speed - eps)); } if (j) { f[i][j] = min(f[i][j], f[i - 1][j - 1] + dist[i - 1] * 1.0 / speed); } } } for (int j = 0; j <= n; ++j) { if (f[n][j] <= hoursBefore + eps) { return j; } } return -1; }};class Solution: def minSkips(self, dist: List[int], speed: int, hoursBefore: int) -> int: n = len(dist) f = [[inf] * (n + 1) for _ in range(n + 1)] f[0][0] = 0 eps = 1e-8 for i, x in enumerate(dist, 1): for j in range(i + 1): if j < i: f[i][j] = min(f[i][j], ceil(f[i - 1][j] + x / speed - eps)) if j: f[i][j] = min(f[i][j], f[i - 1][j - 1] + x / speed) for j in range(n + 1): if f[n][j] <= hoursBefore + eps: return j return - 1Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.