3439. Reschedule Meetings for Maximum Free Time I
Problem Description
You have an event that runs from time t = 0 to time t = eventTime. During this event, there are n scheduled meetings that don't overlap with each other. Each meeting i starts at startTime[i] and ends at endTime[i].
Your task is to reschedule at most k of these meetings to maximize the longest continuous period of free time during the event. When you reschedule a meeting, you can only change its start time while keeping the same duration. The meetings must:
- Remain non-overlapping after rescheduling
- Keep their relative order (if meeting A was before meeting B originally, it must stay before B)
- Stay within the event time bounds (cannot be scheduled outside
[0, eventTime])
For example, if you have an event from time 0 to 10, with meetings at [2,4] and [6,8], the free time periods are [0,2], [4,6], and [8,10]. If you can reschedule 1 meeting (k=1), you could move the first meeting to [0,2] to create a longer continuous free period [2,10] of length 8.
The goal is to find the maximum possible length of continuous free time you can create by optimally rescheduling up to k meetings.
Intuition
When we look at this problem, we need to understand what happens when we reschedule meetings. Initially, we have free time gaps between meetings. When we reschedule a meeting, we're essentially moving it to eliminate one gap and extend another gap.
Think about it this way: if we have free time periods like [gap1] meeting1 [gap2] meeting2 [gap3], and we move meeting1 to the left to fill gap1, then gap1 disappears but gap2 grows by the same amount. We've essentially merged gap1 and gap2 into one continuous free period.
The key insight is that when we reschedule k meetings optimally, we can merge up to k+1 consecutive free time gaps. Why k+1? Because:
- Rescheduling 1 meeting merges 2 gaps (the one before and after it)
- Rescheduling 2 adjacent meetings merges 3 gaps
- Rescheduling
kadjacent meetings mergesk+1gaps
So the problem transforms into: given all the free time gaps in the event, find the maximum sum of any k+1 consecutive gaps.
We can identify n+1 free time gaps:
- Gap before the first meeting:
startTime[0] - 0 - Gaps between consecutive meetings:
startTime[i] - endTime[i-1]for each pair - Gap after the last meeting:
eventTime - endTime[-1]
Once we have these gap lengths in an array nums, finding the maximum sum of k+1 consecutive elements is a classic sliding window problem. We maintain a window of size k+1, slide it through the array, and track the maximum sum encountered.
Learn more about Greedy and Sliding Window patterns.
Solution Implementation
1class Solution: 2 def maxFreeTime( 3 self, eventTime: int, k: int, startTime: List[int], endTime: List[int] 4 ) -> int: 5 # Build array of free time gaps between consecutive events 6 free_time_gaps = [] 7 8 # First gap: from time 0 to the start of first event 9 free_time_gaps.append(startTime[0]) 10 11 # Middle gaps: between end of previous event and start of next event 12 for i in range(1, len(startTime)): 13 gap = startTime[i] - endTime[i - 1] 14 free_time_gaps.append(gap) 15 16 # Last gap: from end of last event to the total event time 17 free_time_gaps.append(eventTime - endTime[-1]) 18 19 # Use sliding window to find maximum sum of k consecutive gaps 20 max_free_time = 0 21 current_window_sum = 0 22 23 for i, gap_duration in enumerate(free_time_gaps): 24 # Add current gap to the window 25 current_window_sum += gap_duration 26 27 # When window size reaches k, start checking for maximum 28 if i >= k: 29 max_free_time = max(max_free_time, current_window_sum) 30 # Remove the leftmost element from window to maintain size k 31 current_window_sum -= free_time_gaps[i - k] 32 33 return max_free_time 341class Solution { 2 public int maxFreeTime(int eventTime, int k, int[] startTime, int[] endTime) { 3 int numberOfEvents = endTime.length; 4 5 // Array to store free time periods between consecutive events 6 // Index i represents the free time before/after event i 7 int[] freeTimePeriods = new int[numberOfEvents + 1]; 8 9 // Free time before the first event 10 freeTimePeriods[0] = startTime[0]; 11 12 // Calculate free time between consecutive events 13 for (int i = 1; i < numberOfEvents; i++) { 14 freeTimePeriods[i] = startTime[i] - endTime[i - 1]; 15 } 16 17 // Free time after the last event until eventTime 18 freeTimePeriods[numberOfEvents] = eventTime - endTime[numberOfEvents - 1]; 19 20 // Find maximum sum of k consecutive free time periods using sliding window 21 int maxFreeTimeSum = 0; 22 int currentWindowSum = 0; 23 24 for (int i = 0; i <= numberOfEvents; i++) { 25 // Add current period to window 26 currentWindowSum += freeTimePeriods[i]; 27 28 // When window size reaches k, update maximum and slide window 29 if (i >= k) { 30 maxFreeTimeSum = Math.max(maxFreeTimeSum, currentWindowSum); 31 // Remove the leftmost element from window 32 currentWindowSum -= freeTimePeriods[i - k]; 33 } 34 } 35 36 return maxFreeTimeSum; 37 } 38} 391class Solution { 2public: 3 int maxFreeTime(int eventTime, int k, vector<int>& startTime, vector<int>& endTime) { 4 int numEvents = endTime.size(); 5 6 // Build array of free time gaps: 7 // - gaps[0]: free time before first event 8 // - gaps[i] for i in [1, n-1]: free time between event i-1 and event i 9 // - gaps[n]: free time after last event 10 vector<int> freeTimeGaps(numEvents + 1); 11 12 // Free time before the first event 13 freeTimeGaps[0] = startTime[0]; 14 15 // Free time between consecutive events 16 for (int i = 1; i < numEvents; ++i) { 17 freeTimeGaps[i] = startTime[i] - endTime[i - 1]; 18 } 19 20 // Free time after the last event 21 freeTimeGaps[numEvents] = eventTime - endTime[numEvents - 1]; 22 23 // Use sliding window to find maximum sum of k consecutive gaps 24 // This represents the maximum free time when skipping k-1 events 25 int maxFreeTimeResult = 0; 26 int windowSum = 0; 27 28 for (int i = 0; i <= numEvents; ++i) { 29 // Add current gap to window 30 windowSum += freeTimeGaps[i]; 31 32 // When window size reaches k, update max and slide window 33 if (i >= k) { 34 maxFreeTimeResult = max(maxFreeTimeResult, windowSum); 35 // Remove the leftmost element from window 36 windowSum -= freeTimeGaps[i - k]; 37 } 38 } 39 40 return maxFreeTimeResult; 41 } 42}; 431/** 2 * Calculates the maximum free time available by skipping k consecutive events 3 * @param eventTime - Total duration of all events 4 * @param k - Number of consecutive events that can be skipped 5 * @param startTime - Array of start times for each event 6 * @param endTime - Array of end times for each event 7 * @returns Maximum free time that can be obtained 8 */ 9function maxFreeTime(eventTime: number, k: number, startTime: number[], endTime: number[]): number { 10 const eventCount: number = endTime.length; 11 12 // Array to store free time gaps between events 13 // Index 0: time from 0 to first event start 14 // Index 1 to n-1: gaps between consecutive events 15 // Index n: time from last event end to total event time 16 const freeTimeGaps: number[] = new Array(eventCount + 1); 17 18 // Calculate free time before the first event 19 freeTimeGaps[0] = startTime[0]; 20 21 // Calculate free time gaps between consecutive events 22 for (let i = 1; i < eventCount; i++) { 23 freeTimeGaps[i] = startTime[i] - endTime[i - 1]; 24 } 25 26 // Calculate free time after the last event 27 freeTimeGaps[eventCount] = eventTime - endTime[eventCount - 1]; 28 29 // Use sliding window to find maximum sum of k consecutive free time gaps 30 let maxFreeTime: number = 0; 31 let currentWindowSum: number = 0; 32 33 for (let i = 0; i <= eventCount; i++) { 34 // Add current gap to the window 35 currentWindowSum += freeTimeGaps[i]; 36 37 // When window size reaches k, update maximum and slide the window 38 if (i >= k) { 39 maxFreeTime = Math.max(maxFreeTime, currentWindowSum); 40 // Remove the leftmost element from the window 41 currentWindowSum -= freeTimeGaps[i - k]; 42 } 43 } 44 45 return maxFreeTime; 46} 47Solution Approach
Based on our intuition, we implement the solution using a sliding window approach:
Step 1: Extract Free Time Intervals
First, we build an array nums containing all free time gaps:
nums[0] = startTime[0]- the gap from event start to first meeting- For middle gaps:
nums[i] = startTime[i] - endTime[i-1]forifrom 1 ton-1 nums[n] = eventTime - endTime[-1]- the gap from last meeting to event end
nums = [startTime[0]] for i in range(1, len(endTime)): nums.append(startTime[i] - endTime[i - 1]) nums.append(eventTime - endTime[-1])
Step 2: Apply Sliding Window
We need to find the maximum sum of k+1 consecutive elements in nums. We use a sliding window technique:
- Initialize
ans = 0to track the maximum sum ands = 0for the current window sum - As we iterate through
nums, we add each element to our current sums - Once our window reaches size
k+1(wheni >= k), we:- Update
answith the maximum of currentansand window sums - Remove the leftmost element from the window by subtracting
nums[i-k]
- Update
ans = s = 0 for i, x in enumerate(nums): s += x if i >= k: ans = max(ans, s) s -= nums[i - k]
The condition i >= k ensures we have exactly k+1 elements in our window (indices 0 to k inclusive).
Time Complexity: O(n) where n is the number of meetings, as we traverse the array once.
Space Complexity: O(n) for storing the nums array.
This approach efficiently finds the maximum continuous free time by identifying which consecutive gaps to merge through rescheduling meetings.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate the solution approach.
Example Input:
eventTime = 10startTime = [2, 5, 8]endTime = [3, 7, 9]k = 1(we can reschedule at most 1 meeting)
Step 1: Identify the free time gaps
First, let's visualize the timeline:
Time: 0 1 2 3 4 5 6 7 8 9 10 Meetings: [M1] [--M2--] [M3] Free: [----] [--] [] []
Now we extract the free time intervals into array nums:
- Gap before first meeting:
startTime[0] - 0 = 2 - 0 = 2 - Gap between M1 and M2:
startTime[1] - endTime[0] = 5 - 3 = 2 - Gap between M2 and M3:
startTime[2] - endTime[1] = 8 - 7 = 1 - Gap after last meeting:
eventTime - endTime[2] = 10 - 9 = 1
So nums = [2, 2, 1, 1]
Step 2: Find maximum sum of k+1 consecutive gaps
Since k = 1, we need to find the maximum sum of k+1 = 2 consecutive elements.
Using the sliding window approach:
- Window size = 2
- Initialize:
ans = 0,s = 0
Iteration process:
i = 0: Addnums[0] = 2to sum →s = 2- Window not full yet (
i < k), don't update answer
- Window not full yet (
i = 1: Addnums[1] = 2to sum →s = 4- Window is full (
i >= k), updateans = max(0, 4) = 4 - Remove leftmost element:
s = 4 - nums[0] = 4 - 2 = 2
- Window is full (
i = 2: Addnums[2] = 1to sum →s = 3- Window is full, update
ans = max(4, 3) = 4 - Remove leftmost element:
s = 3 - nums[1] = 3 - 2 = 1
- Window is full, update
i = 3: Addnums[3] = 1to sum →s = 2- Window is full, update
ans = max(4, 2) = 4 - Remove leftmost element:
s = 2 - nums[2] = 2 - 1 = 1
- Window is full, update
Result: Maximum continuous free time = 4
What does this mean? By rescheduling 1 meeting, we can merge 2 consecutive gaps. The best choice is to merge the first two gaps (each of length 2) by moving meeting M1 to start at time 0. This creates one continuous free period from time 2 to time 5, giving us 4 units of free time.
After rescheduling:
Time: 0 1 2 3 4 5 6 7 8 9 10 Meetings: [M1] [--M2--] [M3] Free: [--------] [] [] (length 4)
Time and Space Complexity
Time Complexity: O(n) where n is the number of meetings (length of startTime and endTime arrays).
The algorithm performs the following operations:
- Building the
numsarray requires iterating through all meetings once:O(n) - The sliding window loop iterates through the
numsarray exactly once:O(n + 1) = O(n)(sincenumshasn + 1elements) - Each operation inside the loop (addition, comparison, subtraction) takes constant time:
O(1)
Therefore, the overall time complexity is O(n) + O(n) = O(n).
Space Complexity: O(n) where n is the number of meetings.
The algorithm uses additional space for:
- The
numsarray which storesn + 1elements (free time gaps between meetings plus gaps at the beginning and end):O(n + 1) = O(n) - A few scalar variables (
ans,s,i,x) which take constant space:O(1)
Therefore, the overall space complexity is O(n).
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Off-by-One Error in Window Size
The most common mistake is misunderstanding that to merge k meetings, we need k+1 consecutive gaps. Many developers incorrectly use a window size of k instead of k+1.
Incorrect Implementation:
# Wrong: Using window size of k if i >= k - 1: # This checks for k elements, not k+1 max_free_time = max(max_free_time, current_window_sum) current_window_sum -= free_time_gaps[i - k + 1]
Why it's wrong: When we reschedule k meetings, we're essentially removing k boundaries between free time gaps, which allows us to merge k+1 consecutive gaps into one continuous period.
Correct Implementation:
# Correct: Using window size of k+1 if i >= k: # This ensures we have k+1 elements (indices 0 to k) max_free_time = max(max_free_time, current_window_sum) current_window_sum -= free_time_gaps[i - k]
2. Edge Case: k Equals or Exceeds Number of Meetings
When k >= n (where n is the number of meetings), we can reschedule all meetings, potentially creating one continuous free period. The code might fail to handle this properly.
Problem Scenario:
- If
k >= len(free_time_gaps) - 1, the sliding window never completes becauseinever reachesk.
Solution:
def maxFreeTime(self, eventTime: int, k: int, startTime: List[int], endTime: List[int]) -> int: free_time_gaps = [] free_time_gaps.append(startTime[0]) for i in range(1, len(startTime)): free_time_gaps.append(startTime[i] - endTime[i - 1]) free_time_gaps.append(eventTime - endTime[-1]) # Handle edge case where k allows rescheduling all or more meetings if k >= len(free_time_gaps) - 1: return eventTime # All meetings can be moved, entire event is free max_free_time = 0 current_window_sum = 0 for i, gap_duration in enumerate(free_time_gaps): current_window_sum += gap_duration if i >= k: max_free_time = max(max_free_time, current_window_sum) current_window_sum -= free_time_gaps[i - k] return max_free_time
3. Forgetting to Handle Empty Meeting Lists
If there are no meetings (startTime and endTime are empty), the entire event time is already free.
Solution:
def maxFreeTime(self, eventTime: int, k: int, startTime: List[int], endTime: List[int]) -> int: # Handle empty meeting list if not startTime: return eventTime # Rest of the implementation...
Is the following code DFS or BFS?
void search(Node root) { if (!root) return; visit(root); root.visited = true; for (Node node in root.adjacent) { if (!node.visited) { search(node); } } }
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
https assets algo monster cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in the window The window
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!