Reschedule Meetings for Maximum Free Time I
MedPrompt
You are given an integer eventTime denoting the duration of an event, where the event occurs from time t = 0 to time t = eventTime.
You are also given two integer arrays startTime and endTime, each of length n. These represent the start and end time of n non-overlapping meetings, where the ith meeting occurs during the time [startTime[i], endTime[i]].
You can reschedule at most k meetings by moving their start time while maintaining the same duration, to maximize the longest continuous period of free time during the event.
The relative order of all the meetings should stay the same and they should remain non-overlapping.
Return the maximum amount of free time possible after rearranging the meetings.
Note that the meetings can not be rescheduled to a time outside the event.
Example 1:
Input: eventTime = 5, k = 1, startTime = [1,3], endTime = [2,5]
Output: 2
Explanation:

Reschedule the meeting at [1, 2] to [2, 3], leaving no meetings during the time [0, 2].
Example 2:
Input: eventTime = 10, k = 1, startTime = [0,2,9], endTime = [1,4,10]
Output: 6
Explanation:

Reschedule the meeting at [2, 4] to [1, 3], leaving no meetings during the time [3, 9].
Example 3:
Input: eventTime = 5, k = 2, startTime = [0,1,2,3,4], endTime = [1,2,3,4,5]
Output: 0
Explanation:
There is no time during the event not occupied by meetings.
Constraints:
1 <= eventTime <= 109n == startTime.length == endTime.length2 <= n <= 1051 <= k <= n0 <= startTime[i] < endTime[i] <= eventTimeendTime[i] <= startTime[i + 1]whereilies in the range[0, n - 2].
Approaches
2 approaches with complexity analysis and trade-offs.
This approach systematically checks every possible way to create a large free time gap. It considers the initial gaps between meetings and then, for each potential gap, calculates the maximum size it can be expanded to by rescheduling meetings on one or both sides, staying within the k move limit. This is done without any precomputation, leading to repeated calculations.
Algorithm
- Initialize
max_free_timewith the largest initial gap (at the start, end, or between any two meetings). - Pre-calculate the duration of each meeting.
- Iterate through each possible split point
ifrom1ton(for a gap after meetingi-1). - For each
i, calculate the cost and duration of packing the prefix meetings0..i-1by iterating fromj=0toi-1. - If the prefix packing cost is
≤ k, calculate the new gapstartTime[i] - (packed_prefix_duration)and updatemax_free_time. - Similarly, for each split point
ifrom0ton-1(for a gap before meetingi), calculate the cost and duration of packing the suffix meetingsi..n-1. - If the suffix packing cost is
≤ k, calculate the new gap(eventTime - packed_suffix_duration) - endTime[i-1]and updatemax_free_time. - For each split point
ifrom0ton, calculate the combined cost of packing both the prefix0..i-1and suffixi..n-1. - If the combined cost is
≤ k, calculate the gapeventTime - total_durationand updatemax_free_time. - Return the final
max_free_time.
Walkthrough
The algorithm first considers all initial free time intervals: startTime[0] (gap at the start), eventTime - endTime[n-1] (gap at the end), and startTime[i] - endTime[i-1] for 1 <= i < n. The maximum of these is our baseline answer.
Then, for each potential gap (including those at the ends), we explore three possibilities of using our k moves:
-
Pack the prefix: For a gap between meetings
i-1andi, we can try to pack all meetings0..i-1to start at time 0. We calculate the cost (number of moves) for this by iterating through these meetings. Ifcost <= k, we calculate the new, larger gap:startTime[i] - (end time of packed prefix). -
Pack the suffix: Similarly, we can try to pack all meetings
i..n-1to end ateventTime. We calculate the cost and, if affordable, the new gap:(start time of packed suffix) - endTime[i-1]. -
Pack both prefix and suffix: We can try to pack both the prefix and suffix parts. We calculate the combined cost. If
cost <= k, the new gap is(start time of packed suffix) - (end time of packed prefix), which simplifies toeventTime - total_duration.
For each split point i, these calculations (costs and durations) are done by iterating through the relevant meetings. The overall maximum free time found across all these scenarios and all split points is the result.
class Solution { public int maxFreeTime(int eventTime, int k, int[] startTime, int[] endTime) { int n = startTime.length; if (n == 0) return eventTime; long[] durations = new long[n]; for (int i = 0; i < n; i++) { durations[i] = (long)endTime[i] - startTime[i]; } long maxFreeTime = 0; // Initial gaps maxFreeTime = Math.max(maxFreeTime, startTime[0]); maxFreeTime = Math.max(maxFreeTime, eventTime - endTime[n - 1]); for (int i = 1; i < n; i++) { maxFreeTime = Math.max(maxFreeTime, (long)startTime[i] - endTime[i - 1]); } for (int i = 0; i <= n; i++) { // Scenario 1: Pack prefix 0..i-1 long prefixDuration = 0; int prefixCost = 0; long currentIdealStart = 0; for (int j = 0; j < i; j++) { if (startTime[j] != currentIdealStart) { prefixCost++; } currentIdealStart += durations[j]; } prefixDuration = currentIdealStart; if (prefixCost <= k) { long gap = (i < n) ? (long)startTime[i] - prefixDuration : (long)eventTime - prefixDuration; maxFreeTime = Math.max(maxFreeTime, gap); } // Scenario 2: Pack suffix i..n-1 long suffixDuration = 0; for (int j = i; j < n; j++) { suffixDuration += durations[j]; } int suffixCost = 0; long currentIdealStartSuffix = eventTime - suffixDuration; for (int j = i; j < n; j++) { if (startTime[j] != currentIdealStartSuffix) { suffixCost++; } currentIdealStartSuffix += durations[j]; } if (suffixCost <= k) { long gap = (i > 0) ? (eventTime - suffixDuration) - endTime[i - 1] : eventTime - suffixDuration; maxFreeTime = Math.max(maxFreeTime, gap); } // Scenario 3: Pack both if (prefixCost + suffixCost <= k) { long totalDuration = prefixDuration + suffixDuration; maxFreeTime = Math.max(maxFreeTime, eventTime - totalDuration); } } return (int)maxFreeTime; }}Complexity
Time
O(N^2). The main loop iterates `N+1` times. Inside this loop, calculating costs and durations for prefixes and suffixes involves nested loops that take O(N) time in total. This results in a quadratic time complexity.
Space
O(N) to store the durations of the meetings. This can be optimized to O(1) if durations are calculated on the fly.
Trade-offs
Pros
Conceptually straightforward, directly modeling the problem's scenarios.
Does not require complex data structures.
Cons
Inefficient for large inputs due to its quadratic time complexity.
Performs many redundant calculations for prefix/suffix costs and durations.
This approach significantly optimizes the brute-force method by pre-calculating all necessary values. Instead of re-computing prefix/suffix durations and their associated rescheduling costs in each iteration, we compute them once and store them in auxiliary arrays. This allows us to evaluate each potential gap scenario in constant time, reducing the overall complexity from quadratic to linear.
Algorithm
- Pre-calculate
durationsfor all meetings inO(N). - Pre-calculate
prefix_sum_durandprefix_movesarrays in a singleO(N)pass from left to right. - Pre-calculate
suffix_sum_durandsuffix_movesarrays in a singleO(N)pass from right to left. - Initialize
max_free_timewith the largest initial gap in the schedule. - Iterate through all split points
ifrom0ton. - For each split, use the precomputed arrays to find the costs and durations for three scenarios in
O(1)time: a. Packing only the prefix. b. Packing only the suffix. c. Packing both prefix and suffix. - If a scenario's cost is within the
klimit, calculate the resulting free time and updatemax_free_time. - Return the final
max_free_time.
Walkthrough
The O(N^2) approach is slow due to redundant calculations. We can optimize it by precomputing the required values. We use four arrays for this:
prefix_sum_dur[i]: Stores the total duration of meetings0toi-1.prefix_moves[i]: Stores the cost (number of moves) to pack meetings0toi-1tightly at the start.suffix_sum_dur[i]: Stores the total duration of meetingsiton-1.suffix_moves[i]: Stores the cost to pack meetingsiton-1tightly at the end.
These arrays can all be computed in O(N) time. Once we have them, we can iterate through all split points i from 0 to n and check the three packing scenarios (prefix only, suffix only, both) in O(1) time for each split.
- Initial Gaps: We first find the maximum of all initial gaps.
- Pack Prefix: If
prefix_moves[i] <= k, the new gap isstartTime[i] - prefix_sum_dur[i](oreventTime - prefix_sum_dur[i]ifi=n). - Pack Suffix: If
suffix_moves[i] <= k, the new gap is(eventTime - suffix_sum_dur[i]) - endTime[i-1](oreventTime - suffix_sum_dur[i]ifi=0). - Pack Both: If
prefix_moves[i] + suffix_moves[i] <= k, the new gap iseventTime - (prefix_sum_dur[i] + suffix_sum_dur[i]).
By checking all these possibilities, we find the maximum achievable free time.
class Solution { public int maxFreeTime(int eventTime, int k, int[] startTime, int[] endTime) { int n = startTime.length; if (n == 0) return eventTime; long[] durations = new long[n]; for (int i = 0; i < n; i++) { durations[i] = (long)endTime[i] - startTime[i]; } long[] prefixSumDur = new long[n + 1]; int[] prefixMoves = new int[n + 1]; for (int i = 1; i <= n; i++) { prefixSumDur[i] = prefixSumDur[i - 1] + durations[i - 1]; prefixMoves[i] = prefixMoves[i - 1]; if (startTime[i - 1] != prefixSumDur[i - 1]) { prefixMoves[i]++; } } long[] suffixSumDur = new long[n + 1]; for (int i = n - 1; i >= 0; i--) { suffixSumDur[i] = suffixSumDur[i + 1] + durations[i]; } int[] suffixMoves = new int[n + 1]; for (int i = n - 1; i >= 0; i--) { suffixMoves[i] = suffixMoves[i + 1]; long idealStartTime = (long)eventTime - suffixSumDur[i]; if (startTime[i] != idealStartTime) { suffixMoves[i]++; } } long maxFreeTime = 0; maxFreeTime = Math.max(maxFreeTime, startTime[0]); maxFreeTime = Math.max(maxFreeTime, eventTime - endTime[n - 1]); for (int i = 1; i < n; i++) { maxFreeTime = Math.max(maxFreeTime, (long)startTime[i] - endTime[i - 1]); } for (int i = 0; i <= n; i++) { if (prefixMoves[i] <= k) { long gap = (i < n) ? (long)startTime[i] - prefixSumDur[i] : (long)eventTime - prefixSumDur[i]; maxFreeTime = Math.max(maxFreeTime, gap); } if (suffixMoves[i] <= k) { long gap = (i > 0) ? (eventTime - suffixSumDur[i]) - endTime[i - 1] : eventTime - suffixSumDur[i]; maxFreeTime = Math.max(maxFreeTime, gap); } if (prefixMoves[i] + suffixMoves[i] <= k) { long totalDuration = prefixSumDur[i] + suffixSumDur[i]; maxFreeTime = Math.max(maxFreeTime, eventTime - totalDuration); } } return (int)maxFreeTime; }}Complexity
Time
O(N). The precomputation steps each take a single pass over the `N` meetings, which is `O(N)`. The final loop to check all scenarios also runs `N+1` times, with each step being `O(1)`. The total time complexity is dominated by these linear passes.
Space
O(N) for storing the four precomputed arrays: `prefixSumDur`, `prefixMoves`, `suffixSumDur`, and `suffixMoves`.
Trade-offs
Pros
Highly efficient with linear time complexity, suitable for large inputs.
Systematically covers all optimal arrangements for creating a single large gap.
Cons
Requires extra space for the precomputed arrays.
Video 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.