Number of Students Doing Homework at a Given Time: Interval Containment Check
You are given two integer arrays startTime and endTime, both of length n, and an integer queryTime. Student i started their homework at startTime[i] and finished at endTime[i]. Return the number of students who were doing their homework at queryTime. A student counts if startTime[i] <= queryTime <= endTime[i].
This is LeetCode 1450: Number of Students Doing Homework at a Given Time. It is an easy problem that boils down to a single pattern: counting how many intervals contain a given point.
Why this problem matters
At first glance, this looks almost too simple to be worth studying. You just loop through each student and check one condition. But the underlying pattern, interval containment, is one of the most frequently recurring ideas in algorithm problems. Recognizing it here helps you spot it in harder settings.
Interval containment checks appear in scheduling problems, event overlap counting, and range queries. The condition start <= query <= end is the same building block that powers solutions to problems like Meeting Rooms, Insert Interval, and My Calendar. Getting comfortable with this check in a simple context makes it second nature when the surrounding logic gets more complex.
This problem also reinforces a useful habit: before reaching for clever data structures, ask whether a plain linear scan is good enough. When n is small and you only have one query, there is no reason to build a segment tree or sort the data. The simplest correct solution wins.
The key insight
A student is doing homework at queryTime if and only if startTime[i] <= queryTime <= endTime[i]. You do not need to sort, merge, or preprocess anything. Just iterate through each student, check the condition, and count the ones that satisfy it.
This is a direct application of the interval containment check: given a closed interval [start, end] and a point q, the point lies inside the interval when start <= q and q <= end.
The solution
def busy_students(start_time: list[int], end_time: list[int], query_time: int) -> int:
count = 0
for start, end in zip(start_time, end_time):
if start <= query_time <= end:
count += 1
return count
The function pairs up each student's start and end times using zip. For each pair, it checks whether queryTime falls within the closed interval [start, end]. Python's chained comparison start <= query_time <= end is equivalent to start <= query_time and query_time <= end, but reads more naturally.
If the condition holds, the student is actively doing homework at the query time, so the counter increments. After checking every student, the function returns the total count.
You can write this even more concisely using sum with a generator expression: return sum(1 for s, e in zip(start_time, end_time) if s <= query_time <= e). This is a common Pythonic pattern for counting elements that match a predicate, and it avoids the need for a separate counter variable.
Visual walkthrough
Let's trace through the example with startTime = [1, 2, 3], endTime = [3, 2, 7], and queryTime = 4. We check each student one at a time and keep a running count.
Step 1: Check Student 0. Is 1 <= 4 <= 3? No, because 4 > 3. Student 0 is not doing homework.
Student 0 finished at time 3, before queryTime 4. count = 0.
Step 2: Check Student 1. Is 2 <= 4 <= 2? No, because 4 > 2. Student 1 is not doing homework.
Student 1 started and finished at time 2. They are done well before queryTime 4. count = 0.
Step 3: Check Student 2. Is 3 <= 4 <= 7? Yes. Student 2 is doing homework. Increment count.
Student 2 started at 3 and finishes at 7. queryTime 4 falls within [3,7]. count = 1. Done.
After checking all three students, only Student 2 has an interval that contains time 4. The answer is 1.
Complexity analysis
| Approach | Time | Space |
|---|---|---|
| Linear scan | O(n) | O(1) |
Time: O(n). You visit each student exactly once and do a constant-time comparison. There is no sorting, no nested loop, and no recursive call. The work scales linearly with the number of students.
Space: O(1). The only extra memory is a single integer counter. You do not create any auxiliary arrays or data structures.
The building blocks
1. Interval containment check
if start <= query_time <= end:
# the point query_time lies inside [start, end]
This is the core test for whether a point falls within a closed interval. It shows up in many interval problems. In Insert Interval, you use a similar check to decide whether two intervals overlap. In Meeting Rooms, you check whether any pair of intervals has a point in common. Recognizing this building block lets you decompose interval problems into smaller, familiar pieces.
2. Counting with a predicate
count = sum(1 for s, e in zip(start_time, end_time) if s <= query_time <= e)
The "count items matching a condition" pattern is everywhere in Python. You can use sum with a generator that yields 1 for each match. This is equivalent to the explicit loop with a counter, but it communicates intent more directly: "count the things where this is true."
Edge cases
- queryTime before all intervals. If
queryTimeis smaller than everystartTime[i], no student has started yet. The answer is 0. - queryTime after all intervals. If
queryTimeis larger than everyendTime[i], all students have finished. The answer is 0. - queryTime exactly at a boundary. If
queryTimeequalsstartTime[i]orendTime[i], the student still counts. The interval is closed on both ends. - Single student. With n = 1, the answer is either 0 or 1. The logic does not change.
- All students active. If every interval contains
queryTime, the answer equals n. - Identical intervals. If every student has the same start and end time, the answer depends only on whether
queryTimefalls in that single interval. - Zero-length intervals. A student with
startTime[i] == endTime[i]is only doing homework at that exact time. IfqueryTimematches, they count.
From understanding to recall
The code for this problem is short, but the pattern it uses is worth committing to memory. The interval containment check, start <= query <= end, is a building block you will use over and over in interval problems. You do not want to rederive it each time or second-guess whether the comparisons should be strict or non-strict.
The best way to internalize a building block is to practice it in isolation. Write the one-liner version from memory. Then write the explicit loop version. Then apply it to a slightly harder problem like checking whether two intervals overlap (which is really just two containment checks combined). Each repetition strengthens the connection until the pattern becomes automatic.
Once the containment check is automatic, problems like Insert Interval and Meeting Rooms become easier because you spend your mental energy on the higher-level logic instead of wrestling with boundary conditions.
Related posts
- Merge Intervals - Working with interval start/end times in a more complex setting
- Insert Interval - Another interval problem that builds on containment logic
- Non-overlapping Intervals - Interval scheduling using similar start/end comparisons
This problem is a clean entry point into the world of interval algorithms. It asks one question, uses one pattern, and has one loop. That simplicity makes it the perfect place to lock in the interval containment check before you encounter it in harder problems where distractions abound.