3440. Reschedule Meetings for Maximum Free Time II
Problem Description
You are given an integer eventTime
denoting the duration of an event. Additionally, you have two integer arrays startTime
and endTime
, each of length n
. These arrays represent the start and end times of n
non-overlapping meetings that occur during this event, ranging from time t = 0
to t = eventTime
. The i-th
meeting occurs during the time interval [startTime[i], endTime[i]]
.
Your task is to reschedule at most one meeting by changing its start time while keeping the duration the same, ensuring that the meetings remain non-overlapping. The goal is to maximize the longest continuous period of free time during the event.
Return the maximum amount of free time possible after rearranging the meetings. Meetings cannot be moved outside the event's timeframe, and they must remain non-overlapping. It's allowable for the order of the meetings to change after rescheduling one.
Intuition
To solve the problem, we need to focus on ensuring that meetings are rescheduled optimally for maximizing the free time periods, called gaps, between the meetings. Here's a structured approach to the problem:
-
Compute Left Gaps: Calculate the free time between each meeting and the previous one when considering the event as starting. Maintain a running maximum of this gap through a left-to-right traversal.
-
Compute Right Gaps: Calculate the free time between each meeting and the next one up until the event ends. This needs a right-to-left traversal to store the maximum gaps on the right.
-
Evaluate Maximum Free Time:
- For each meeting, using the stored left and right gaps, compute the potential maximum free time considering the possibility of rescheduling the meeting.
- Consider the free time available if the current meeting were rescheduled, utilizing the left and right gaps to determine the best possible slot.
-
Selection of Rescheduling:
- For each meeting, evaluate if shifting would allow a greater continuous free time while keeping all the meetings non-overlapping.
- The objective is to maximize the sum of left gap, right gap, and the meeting's interval if rescheduling is feasible.
This method effectively allows us to evaluate and maximize free time by efficiently using the precomputed gaps and making a single strategic reschedule decision.
Learn more about Greedy patterns.
Solution Approach
The solution leverages a dynamic approach by calculating gaps and efficiently determining where a meeting can be rescheduled to maximize free time. Here's a breakdown of the implemented algorithm and strategy:
-
Initialization:
- Determine the number of meetings
n
. - Use an array
left_gaps
to store the maximum gap between the start of the event and the current meeting if measured from the left. Initialize the first gap withstartTime[0]
. - Use a second array
right_gaps
to store the maximum gap between the end of the current meeting and the end of the event if measured from the right. Initialize this witheventTime - endTime[-1]
.
- Determine the number of meetings
-
Calculate Left Gaps:
- Iterate over meetings from the start to end.
- For each meeting
i
, compute and store the maximum gap found from the left side up to meetingi
, usingleft_gaps[i] = max(left_gaps[i - 1], startTime[i] - endTime[i - 1])
.
-
Calculate Right Gaps:
- Iterate over meetings from end to start.
- For each meeting
i
, compute and store the maximum gap found from the right side for meetings afteri
, usingright_gaps[i] = max(right_gaps[i + 1], startTime[i + 1] - endTime[i])
.
-
Determine Possible Rescheduling:
- Iterate through each meeting to calculate the potential maximum free time:
- Calculate the
left_gap
directly fromleft_gaps
. - Calculate the
right_gap
directly fromright_gaps
. - If rescheduling a meeting can overcome a gap on either side without conflict, consider the interval of the meeting for inclusion in the potential free time calculation.
- Compute the potential free time as the sum of
left_gap
,right_gap
, and interval (if applicable).
- Calculate the
- Iterate through each meeting to calculate the potential maximum free time:
-
Compute Result:
- Throughout this process, maintain a variable
res
to store the maximum free time computed. - The final result is the maximum value of free time possible after evaluating all potential single-meeting rescheduling options.
- Throughout this process, maintain a variable
This approach efficiently preprocesses gaps using dynamic programming techniques, enabling quick evaluation of rescheduling impacts to achieve maximal free time.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's illustrate the solution approach using a small example:
Consider the following:
eventTime = 20
startTime = [2, 6, 10]
endTime = [4, 8, 12]
Step 1: Initialization
- Number of meetings
n = 3
. - Initialize
left_gaps
to store maximum gaps from the start of the event:left_gaps[0] = startTime[0] = 2
- Initialize
right_gaps
to store maximum gaps to the end of the event:right_gaps[2] = eventTime - endTime[2] = 20 - 12 = 8
Step 2: Calculate Left Gaps
-
For
i = 1
:- Calculate the gap before meeting 1:
startTime[1] - endTime[0] = 6 - 4 = 2
- Update:
left_gaps[1] = max(left_gaps[0], 2) = 2
- Calculate the gap before meeting 1:
-
For
i = 2
:- Calculate the gap before meeting 2:
startTime[2] - endTime[1] = 10 - 8 = 2
- Update:
left_gaps[2] = max(left_gaps[1], 2) = 2
- Calculate the gap before meeting 2:
Step 3: Calculate Right Gaps
-
For
i = 1
:- Calculate the gap after meeting 1:
startTime[2] - endTime[1] = 10 - 8 = 2
- Update:
right_gaps[1] = max(right_gaps[2], 2) = 8
- Calculate the gap after meeting 1:
-
For
i = 0
:- Calculate the gap after meeting 0:
startTime[1] - endTime[0] = 6 - 4 = 2
- Update:
right_gaps[0] = max(right_gaps[1], 2) = 8
- Calculate the gap after meeting 0:
Step 4: Determine Possible Rescheduling
Evaluate each meeting to see potential free time:
-
Rescheduling Meeting 0:
- Available gaps:
left_gap = 0
,right_gap = right_gaps[0] = 8
- Potential free time:
8
(considering moving the meeting around other gaps doesn't extend free time)
- Available gaps:
-
Rescheduling Meeting 1:
- Available gaps:
left_gap = left_gaps[1] = 2
,right_gap = right_gaps[1] = 8
- Potential free time:
2 + 8 = 10
(consider the full gap before or after)
- Available gaps:
-
Rescheduling Meeting 2:
- Available gaps:
left_gap = left_gaps[2] = 2
,right_gap = 0
- Potential free time:
2
(limited options)
- Available gaps:
Step 5: Compute Result
The maximum free time possible after evaluating rescheduling each meeting is 10
. Thus, by rescheduling meeting 1 optimally, we can maximize the free time available during the event.
Solution Implementation
1from typing import List
2
3class Solution:
4 def maxFreeTime(
5 self, eventTime: int, startTime: List[int], endTime: List[int]
6 ) -> int:
7 n = len(startTime) # Total number of meetings
8 max_free_time = 0 # Variable to hold the maximum free time found
9
10 # Calculate the maximum gaps from the left side
11 left_gaps = [0] * n
12 left_gaps[0] = startTime[0] # Free time before the first meeting starts
13 for i in range(1, n):
14 left_gaps[i] = max(left_gaps[i - 1], startTime[i] - endTime[i - 1])
15
16 # Calculate the maximum gaps from the right side
17 right_gaps = [0] * n
18 right_gaps[n - 1] = eventTime - endTime[-1] # Free time after the last meeting ends
19 for i in range(n - 2, -1, -1):
20 right_gaps[i] = max(right_gaps[i + 1], startTime[i + 1] - endTime[i])
21
22 # Compute the maximum free time by evaluating each meeting
23 for i in range(n):
24 # Calculate the gap before the current meeting
25 left_gap = left_gaps[i] if i == 0 else startTime[i] - endTime[i - 1]
26 # Calculate the gap after the current meeting
27 right_gap = right_gaps[i] if i == n - 1 else startTime[i + 1] - endTime[i]
28
29 # Calculate the total interval of free time
30 interval = 0
31 if (
32 i != 0
33 and left_gaps[i - 1] >= (endTime[i] - startTime[i])
34 or i != n - 1
35 and right_gaps[i + 1] >= (endTime[i] - startTime[i])
36 ):
37 interval = endTime[i] - startTime[i]
38
39 # Update the maximum free time found
40 max_free_time = max(max_free_time, left_gap + interval + right_gap)
41
42 return max_free_time
43
1import java.util.List;
2
3class Solution {
4 public int maxFreeTime(int eventTime, List<Integer> startTime, List<Integer> endTime) {
5 int n = startTime.size(); // Total number of meetings
6 int maxFreeTime = 0; // Variable to store maximum free time
7
8 // Calculate maximum gaps from the left side
9 int[] leftGaps = new int[n];
10 leftGaps[0] = startTime.get(0); // Free time before the first meeting starts
11 for (int i = 1; i < n; i++) {
12 leftGaps[i] = Math.max(leftGaps[i - 1], startTime.get(i) - endTime.get(i - 1));
13 }
14
15 // Calculate maximum gaps from the right side
16 int[] rightGaps = new int[n];
17 rightGaps[n - 1] = eventTime - endTime.get(n - 1); // Free time after the last meeting ends
18 for (int i = n - 2; i >= 0; i--) {
19 rightGaps[i] = Math.max(rightGaps[i + 1], startTime.get(i + 1) - endTime.get(i));
20 }
21
22 // Compute maximum free time by evaluating each meeting
23 for (int i = 0; i < n; i++) {
24 // Calculate the gap before the current meeting
25 int leftGap = (i == 0) ? leftGaps[i] : startTime.get(i) - endTime.get(i - 1);
26 // Calculate the gap after the current meeting
27 int rightGap = (i == n - 1) ? rightGaps[i] : startTime.get(i + 1) - endTime.get(i);
28
29 // Calculate the total interval of free time
30 int interval = 0;
31 if ((i != 0 && leftGaps[i - 1] >= (endTime.get(i) - startTime.get(i)))
32 || (i != n - 1 && rightGaps[i + 1] >= (endTime.get(i) - startTime.get(i)))) {
33 // Interval only relevant if the gap exists
34 interval = endTime.get(i) - startTime.get(i);
35 }
36
37 // Update the maximum free time found
38 maxFreeTime = Math.max(maxFreeTime, leftGap + interval + rightGap);
39 }
40
41 return maxFreeTime;
42 }
43}
44
1#include <vector>
2#include <algorithm>
3using namespace std;
4
5class Solution {
6public:
7 int maxFreeTime(int eventTime, vector<int>& startTime, vector<int>& endTime) {
8 int n = startTime.size(); // Total number of meetings
9 int maxFreeTime = 0; // Variable to hold the maximum free time found
10
11 // Calculate the maximum gaps from the left side
12 vector<int> leftGaps(n, 0);
13 leftGaps[0] = startTime[0]; // Free time before the first meeting starts
14 for (int i = 1; i < n; ++i) {
15 leftGaps[i] = max(leftGaps[i - 1], startTime[i] - endTime[i - 1]);
16 }
17
18 // Calculate the maximum gaps from the right side
19 vector<int> rightGaps(n, 0);
20 rightGaps[n - 1] = eventTime - endTime[n - 1]; // Free time after the last meeting ends
21 for (int i = n - 2; i >= 0; --i) {
22 rightGaps[i] = max(rightGaps[i + 1], startTime[i + 1] - endTime[i]);
23 }
24
25 // Compute the maximum free time by evaluating each meeting
26 for (int i = 0; i < n; ++i) {
27 // Calculate the gap before the current meeting
28 int leftGap = (i == 0) ? leftGaps[i] : startTime[i] - endTime[i - 1];
29 // Calculate the gap after the current meeting
30 int rightGap = (i == n - 1) ? rightGaps[i] : startTime[i + 1] - endTime[i];
31
32 // Calculate the total interval of free time
33 int interval = 0;
34 if ((i != 0 && leftGaps[i - 1] >= (endTime[i] - startTime[i]))
35 || (i != n - 1 && rightGaps[i + 1] >= (endTime[i] - startTime[i]))) {
36 interval = endTime[i] - startTime[i];
37 }
38
39 // Update the maximum free time found
40 maxFreeTime = max(maxFreeTime, leftGap + interval + rightGap);
41 }
42
43 return maxFreeTime;
44 }
45};
46
1// Importing List type from standard library for type safety
2type List = number[];
3
4// Function to calculate the maximum free time between meetings
5function maxFreeTime(eventTime: number, startTime: List, endTime: List): number {
6 const n = startTime.length; // Total number of meetings
7 let maxFreeTime = 0; // Variable to hold the maximum free time found
8
9 // Calculate the maximum gaps from the left side
10 const leftGaps: List = Array(n).fill(0);
11 leftGaps[0] = startTime[0]; // Free time before the first meeting starts
12 for (let i = 1; i < n; i++) {
13 leftGaps[i] = Math.max(leftGaps[i - 1], startTime[i] - endTime[i - 1]);
14 }
15
16 // Calculate the maximum gaps from the right side
17 const rightGaps: List = Array(n).fill(0);
18 rightGaps[n - 1] = eventTime - endTime[n - 1]; // Free time after the last meeting ends
19 for (let i = n - 2; i >= 0; i--) {
20 rightGaps[i] = Math.max(rightGaps[i + 1], startTime[i + 1] - endTime[i]);
21 }
22
23 // Compute the maximum free time by evaluating each meeting
24 for (let i = 0; i < n; i++) {
25 // Calculate the gap before the current meeting
26 const leftGap = i === 0 ? startTime[i] : startTime[i] - endTime[i - 1];
27 // Calculate the gap after the current meeting
28 const rightGap = i === n - 1 ? eventTime - endTime[i] : startTime[i + 1] - endTime[i];
29
30 // Calculate the total interval of free time
31 let interval = 0;
32 if (
33 (i !== 0 && leftGaps[i - 1] >= (endTime[i] - startTime[i])) ||
34 (i !== n - 1 && rightGaps[i + 1] >= (endTime[i] - startTime[i]))
35 ) {
36 interval = endTime[i] - startTime[i];
37 }
38
39 // Update the maximum free time found
40 maxFreeTime = Math.max(maxFreeTime, leftGap + interval + rightGap);
41 }
42
43 return maxFreeTime;
44}
45
Time and Space Complexity
The time complexity of the code is O(n)
, where n
is the number of meetings (startTime
and endTime
lists' length). This is because the algorithm processes each meeting in several linear scans (left_gaps
, right_gaps
, and the final for loop), making it a linear time complexity operation.
The space complexity is O(n)
as well, due to the use of two additional arrays, left_gaps
and right_gaps
, each of which holds n
elements.
Learn more about how to find time and space complexity quickly.
How would you design a stack which has a function min
that returns the minimum element in the stack, in addition to push
and pop
? All push
, pop
, min
should have running time O(1)
.
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
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
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Donβt Miss This!