Solving LeetCode Meeting Rooms Problem for Data Science Interviews
Explaining two possible Python solutions to the LeetCode Meeting Rooms problem which is one of the most interesting and common algorithm problems.
Modern businesses collect and utilize increasingly large volumes of data, so competent data scientists with a diverse set of skills are always in high demand. If you’re struggling to find a job, it might be a good idea to complement your skill set by learning a new data science skill like Python.
Unlike SQL, Python allows you to build complex algorithms, do complex data analysis and turn raw data into actionable insights. Mastering Python will make you more valuable to potential employers, which will allow you to command a higher salary and advance your career faster.
During data science interviews, data scientists are often asked to solve a Python challenge. In this article, we will explain two possible solutions to one of the most interesting and common algorithm problems.
LeetCode Meeting Rooms Problem
We are given a list of intervals, which represent the start and end times of meetings. We need to create an algorithm that checks if the person can attend all of these meetings. If we find that meetings do not overlap, we return true, if not, false.
Solving the LeetCode Meeting Rooms Problem
One of the biggest and the most common mistakes is misinterpreting the question itself. This LeetCode meeting rooms question has a fairly simple description, so you can afford to read it multiple times. Make sure to pay close attention to every word, and understand all conditions.
Framework to Solve this LeetCode Meeting Rooms Problem
Even easy Python challenges might seem daunting when you read them for the first time. However, you can create and follow a framework to easily wrap your head around the most important aspects of the question, such as: what you are being asked, possible limitations, and a logical approach to solving the question.
Here is our framework for solving the Meeting Rooms problem. It is applicable to any other challenges as well:
1) Understand your data
- Pay attention to available data - its type, formatting, and possible constraints. If you’re working with a list, pay attention to each list item as well.
- Based on data and its format, anticipate whether or not you’ll have to aggregate or transform data.
- Think about how data can be translated into the real world. Based on that, make logical assumptions.
- Look at available data and try to logically connect it with the answer.
- Consider data constraints to make the algorithm always returns the right answer, even for edge cases.
2) Formulate your approach
- Understand what the question asks. In this case, it doesn’t ask to record and return overlapping meetings, or the number of such instances. We have to return a boolean value - true if one person can attend all the meetings, false otherwise.
- To answer this LeetCode meeting rooms question, you will have to set conditions to identify if meetings overlap or not. Consider the available data at your disposal - start and end times. If you had information about the start and end times of meetings in the real world, how would you determine if they overlap?
- Think about possible edge cases. For example, if one meeting ends at the exact same moment as the other starts, what should be the answer?
- Pay attention to the formulation of the question. We should return true only if none of the meetings overlap. If we find a pair that overlaps, we return false, even if thousands of other meetings do not overlap.
- Consider if it is possible to avoid checking each meeting against all other meetings.
- Keep track of your thinking process by taking notes.
3) Code execution
- Break down the solution into multiple steps. Write them one at a time.
- Decide which Python features you are going to use. In this case, you have to compare every item in the list with all other items in the list, so you need a for loop.
- Write a condition to compare starting and ending times for each meeting in the list.
- Two meetings overlap if one of them starts later than the other, and that same meeting starts earlier than the other ends. If these conditions are met, meetings overlap.
- Handle possible edge cases, such as when one meeting ends and another starts right away.
- Decide whether you will create a function to compare two meetings, or write an inline condition.
Understand Your Data
Understanding available data can prepare you for possible challenges to answering the question.
We have one simple input, which is a list of meeting intervals. Each list item contains two integers to describe the start and end time of the meeting. Numbers represent arbitrary units of time on linear progression of time. Small numbers represent events that happen early. Bigger numbers mean that the event happens later.
This LeetCode meeting rooms question asks if the person can attend all the meetings in the list.
If one meeting ends at specific time, and another one starts right away, these meetings do not overlap.
This section provides information about possible input values.
The first bullet points tells us that the maximum number of intervals in the list is 10^4.
It also tells us that there are always 2 numbers in each list item - numbers that represent the start and end of the meeting.
It also sets the limit for minimum starting time - 0. The maximum is 10^6.
A straightforward approach to solve this LeetCode meeting rooms problem.
Formulate Your Approach
In this LeetCode meeting rooms question, we are given a list of meetings. We have to determine whether a person can attend all the meetings. This is only possible if meetings do not overlap. In other words, meetings must happen at different times, one after another.
We will need to go through every meeting in the list. Even if one of the meetings overlaps with the other, it returns false.
Checking if two meetings overlap will be an essential step towards solving this question. First, it’s important to understand that each meeting is a list of two numbers. The first number represents starting time, and the second represents ending time.
In simple words, we can say that meetings overlap if one starts while the other still hasn’t finished. We will have to turn this condition into Python code.
Look at these two illustrations to visualize the question. Here we have an example of two meetings that do not overlap:
And here are two meetings that do overlap:
In this code, we have a main function with a descriptive name canAttendMeetings, which takes two arguments: self - referring to an instance of a class, and a list of intervals. It will output a boolean. true if meetings do not overlap, and false if they do.
class Solution: def canAttendMeetings(self, intervals: List[List[int]]) -> bool: def overlap(interval1: List[int], interval2: List[int]) -> bool: return (interval1 >= interval2 and interval1 < interval2 or interval2 >= interval1 and interval2 < interval1) for i in range(len(intervals)): for j in range(i + 1, len(intervals)): if overlap(intervals[i], intervals[j]): return False return True
In the function body, we will define a function which will accept two intervals as arguments. It will contain a condition to determine if two meetings overlap.
We know that two meetings overlap if one starts while the other hasn’t finished. We have to translate this logical condition into Python.
First, we will check if one of the meetings starts after (or at the same time as) the second one starts, but also if it starts before the second one ends. Keep in mind that a higher number means that the event happens later. We use or logical operator to handle both intervals.
Then we define two nested loops. We need a main loop and a nested loop to check all possible combinations of meetings.
Finally, we have an if statement. It has a condition that if two meetings overlap, our main algorithm should return false. If not, by default it will return true.
We can rewrite the overlap function to be much more succinct. We can simply check if the minimum end time (when the earlier meeting ends) is less than the maximum start time (when the later meeting starts). This way, our code looks cleaner and we have to perform less calculations.
def overlap(interval1: List[int], interval2: List[int]) -> bool: return (min(interval1, interval2) > max(interval1, interval2))
The shorter and smarter solution
Formulate Your Approach
Logically, meetings that overlap must happen in close time proximity to one another. You can answer the question more efficiently if you arrange meetings in the list from the earliest to latest. This way, we will have to check each meeting not against all other meetings, but only against the one that follows it.
If two consecutive meetings do not overlap, and this holds true for all meetings in the list, then we can be sure that all meetings happen at different times.
Once again, even if we find one pair of meetings that overlap, our algorithm must return false.
This approach is better for multiple reasons. First, it is more efficient, because we don’t have to check each meeting against all other meetings in the list. For a long list of meetings, this will give a significant improvement in speed of the function. More importantly, we achieve this without using any additional memory space.
Second, the code is shorter and easier to read. The algorithm itself is fairly straightforward and logical. This makes it easier for other developers, as well as other parties to understand your code.
This algorithm improves upon the last one in almost every possible way. Choosing this approach will impress interviewers and make them more likely to hire you.
In this approach, we use the .sort() function to arrange meetings in chronological order - from the earliest to the latest. Then we create a loop to go over each meeting and compare it with the meeting that follows it.
The meeting on position i will be compared with the meeting on position i + 1. For instance, the first meeting will be compared with the second, the second with third, and so on until the end.
Don’t forget that in Python, indexes start counting from 0. So index 0 represents the first item in the list. The second item is on index 1, and so on.
class Solution: def canAttendMeetings(self, intervals: List[List[int]]) -> bool: intervals.sort() for i in range(len(intervals) - 1): if intervals[i] > intervals[i + 1]: return False return True
By applying the sort method on our list, we arranged meetings by their starting time, from earliest to latest. However, there’s still a chance that meetings last particularly long and overlap with meetings that start at a later time.
To check if they overlap, we check if the ending time of the earlier meeting is less than (happens before) the starting time of the one that follows it.
LeetCode allows you to run your algorithms with a sample input.
Our sample input will be a list of three meetings. One that lasts from 0 to 30, another lasts from 5 to 10, and the last one from 15 to 20. As you can probably guess, the last two meetings overlap with the first one. If we designed our algorithm correctly, it should return false for this input.
Our algorithm does in fact return false, so it is accepted. Thanks to improvements in efficiency, execution time is just 69ms.
Comparison of Approaches to Solve this LeetCode Meeting Rooms Question
The main difference between two algorithms is how we approach this LeetCode meeting rooms problem. In the first function, we approach it directly. It is a brute force approach that consumes significant resources. In an interview, writing the first algorithm will show that you know Python features and can write error-free code. But it does not say much about the efficiency of your code.
The second algorithm is a better answer than the first in many ways. It is based on a simple realization that we only need to compare meetings that happen in close time proximity to one another. We use a sort function to arrange meetings from the earliest starting times to the latest. Then we simply compare each meeting with its subsequent meeting.
The biggest advantage of the second algorithm is that it eliminates a lot of inefficiency. It eliminates the need for a nested loop. This leads to significant gains in execution time, especially if the size of inputs is large.
Also, instead of a complex function, the second solution uses a simple condition to determine if the meetings overlap. We simply check if the earlier of two meetings ends before the next one begins. If it does, the function correctly determines that the meetings do not overlap. This is much easier to understand, and more readable than using the function.
Candidates who can write efficient Python algorithms can impress interviewers and find it easier to start their data science careers. It takes time and practice to become fluent in Python. Check out our post “Top 30 Python interview questions” to get an overview of the types of Python questions asked in data science interviews.
The best way to practice writing algorithms in Python is to start with easy questions like this one or LeetCode two sum problem, and then move on to questions like LeetCode Coin Change Problem or LeetCode Word Break Problem. Despite the simplicity, there is a lot of nuance to these questions. It’s challenging enough to teach you how to write more readable, efficient, and consistent code.