3450. Maximum Students on a Single Bench 🔒
Problem Description
You are given a 2D integer array called students
, where each element students[i] = [student_id, bench_id]
indicates that a student with ID student_id
is sitting on bench number bench_id
.
Your task is to find the maximum number of unique students sitting on any single bench. If there are no students in the input array, return 0.
An important detail to note: The same student can appear multiple times on the same bench in the input data (multiple entries with the same student_id
and bench_id
), but when counting students on a bench, each unique student should only be counted once.
For example:
- If the input contains
[[1, 2], [1, 2], [3, 2]]
, bench 2 has only 2 unique students (student 1 and student 3), not 3. - The goal is to find which bench has the most unique students and return that count.
The solution uses a hash table with sets to track unique students per bench. For each bench, it maintains a set of student IDs (automatically handling duplicates), then returns the size of the largest set.
Intuition
The key insight is recognizing that we need to count unique students per bench, not total occurrences. When we see multiple entries for the same student on the same bench, we should count that student only once for that bench.
This naturally leads us to think about using a data structure that automatically handles uniqueness - a set. Sets inherently prevent duplicates, so if we add the same student ID multiple times, it will only be stored once.
Since we need to track students for multiple benches, we need a way to organize our sets by bench ID. This points us toward using a hash table (dictionary) where:
- Each key represents a bench ID
- Each value is a set containing all unique student IDs on that bench
As we iterate through the input array, we can simply add each student to the corresponding bench's set. The set automatically handles the deduplication for us - if student 1 appears on bench 2 multiple times, adding them to d[2]
repeatedly won't increase the set size beyond 1 for that student.
Once we've processed all entries, finding the answer becomes straightforward: we just need to find which bench's set has the most elements. This is simply the maximum size among all the sets in our hash table.
The elegance of this approach is that we let the data structures do the heavy lifting - the hash table organizes by bench, the sets handle uniqueness, and we just need to find the maximum size at the end.
Solution Approach
The solution uses a hash table with sets to efficiently track unique students on each bench.
Step-by-step implementation:
-
Initialize the data structure: We create a
defaultdict(set)
calledd
. This is a hash table where:- Keys are bench IDs
- Values are sets that will store unique student IDs
- Using
defaultdict(set)
means if we access a bench ID that doesn't exist yet, it automatically creates an empty set for it
-
Process the student data: We iterate through each entry in the
students
array:for student_id, bench_id in students: d[bench_id].add(student_id)
- For each
[student_id, bench_id]
pair, we add thestudent_id
to the set corresponding tobench_id
- The
add()
operation on a set ensures uniqueness - if the same student ID is added multiple times to the same bench's set, it only counts once
- For each
-
Find the maximum: After processing all entries, we need to find which bench has the most unique students:
return max(map(len, d.values()))
d.values()
gives us all the sets (one for each bench)map(len, d.values())
applies thelen
function to each set, giving us the count of unique students per benchmax()
returns the largest count among all benches
-
Handle edge case: The initial check
if not students: return 0
handles the case where the input array is empty.
Time Complexity: O(n)
where n
is the number of entries in the students array, as we iterate through the array once and set operations are O(1)
on average.
Space Complexity: O(n)
in the worst case where all entries are unique student-bench combinations.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate how the solution works.
Input: students = [[1, 2], [3, 2], [1, 2], [4, 5], [5, 5], [1, 5]]
Step 1: Initialize the hash table
We create an empty defaultdict(set)
called d = {}
Step 2: Process each student-bench pair
-
Process
[1, 2]
: Add student 1 to bench 2's setd = {2: {1}}
-
Process
[3, 2]
: Add student 3 to bench 2's setd = {2: {1, 3}}
-
Process
[1, 2]
: Add student 1 to bench 2's set (already exists, no change)d = {2: {1, 3}}
-
Process
[4, 5]
: Add student 4 to bench 5's setd = {2: {1, 3}, 5: {4}}
-
Process
[5, 5]
: Add student 5 to bench 5's setd = {2: {1, 3}, 5: {4, 5}}
-
Process
[1, 5]
: Add student 1 to bench 5's setd = {2: {1, 3}, 5: {1, 4, 5}}
Step 3: Find the maximum number of unique students
- Bench 2 has 2 unique students: {1, 3}
- Bench 5 has 3 unique students: {1, 4, 5}
- Maximum = 3
Output: 3
Notice how student 1 appearing twice on bench 2 didn't increase the count for that bench, and how student 1 can be counted on both bench 2 and bench 5 since we're looking for the maximum per single bench, not across all benches.
Solution Implementation
1from typing import List
2from collections import defaultdict
3
4class Solution:
5 def maxStudentsOnBench(self, students: List[List[int]]) -> int:
6 # Handle empty input case
7 if not students:
8 return 0
9
10 # Create a dictionary to map bench_id to set of student_ids
11 # Using defaultdict with set to automatically initialize empty sets
12 bench_to_students = defaultdict(set)
13
14 # Iterate through each student-bench pair
15 for student_id, bench_id in students:
16 # Add student_id to the set of students for this bench
17 bench_to_students[bench_id].add(student_id)
18
19 # Find the maximum number of students on any single bench
20 # by getting the length of each set and returning the maximum
21 return max(map(len, bench_to_students.values()))
22
1class Solution {
2 /**
3 * Finds the maximum number of students that can be seated on any single bench.
4 *
5 * @param students A 2D array where each element [studentId, benchId] represents
6 * a student and their assigned bench
7 * @return The maximum number of students on any single bench
8 */
9 public int maxStudentsOnBench(int[][] students) {
10 // Map to store bench ID as key and set of student IDs as value
11 Map<Integer, Set<Integer>> benchToStudentsMap = new HashMap<>();
12
13 // Iterate through each student-bench assignment
14 for (int[] assignment : students) {
15 int studentId = assignment[0];
16 int benchId = assignment[1];
17
18 // Add student to the corresponding bench's set of students
19 // Create a new HashSet if the bench doesn't exist in the map yet
20 benchToStudentsMap.computeIfAbsent(benchId, k -> new HashSet<>()).add(studentId);
21 }
22
23 // Track the maximum number of students on any bench
24 int maxStudents = 0;
25
26 // Iterate through all benches and find the one with the most students
27 for (Set<Integer> studentsOnBench : benchToStudentsMap.values()) {
28 maxStudents = Math.max(maxStudents, studentsOnBench.size());
29 }
30
31 return maxStudents;
32 }
33}
34
1class Solution {
2public:
3 int maxStudentsOnBench(vector<vector<int>>& students) {
4 // Map to store bench ID -> set of unique student IDs on that bench
5 unordered_map<int, unordered_set<int>> benchToStudents;
6
7 // Process each student-bench pair
8 for (const auto& pair : students) {
9 int studentId = pair[0];
10 int benchId = pair[1];
11
12 // Add student to the corresponding bench
13 // Using set ensures each student is counted only once per bench
14 benchToStudents[benchId].insert(studentId);
15 }
16
17 // Find the maximum number of unique students on any single bench
18 int maxStudents = 0;
19 for (const auto& [benchId, studentSet] : benchToStudents) {
20 int studentsOnThisBench = static_cast<int>(studentSet.size());
21 maxStudents = max(maxStudents, studentsOnThisBench);
22 }
23
24 return maxStudents;
25 }
26};
27
1/**
2 * Finds the maximum number of students sitting on any single bench
3 * @param students - 2D array where each element is [studentId, benchId]
4 * @returns The maximum number of students on any bench
5 */
6function maxStudentsOnBench(students: number[][]): number {
7 // Map to store bench ID as key and set of student IDs as value
8 const benchToStudentsMap: Map<number, Set<number>> = new Map();
9
10 // Group students by their bench ID
11 for (const [studentId, benchId] of students) {
12 // Initialize set for new bench if not exists
13 if (!benchToStudentsMap.has(benchId)) {
14 benchToStudentsMap.set(benchId, new Set<number>());
15 }
16 // Add student to the bench's set of students
17 benchToStudentsMap.get(benchId)!.add(studentId);
18 }
19
20 // Track the maximum number of students on any bench
21 let maxStudents: number = 0;
22
23 // Iterate through all benches to find the maximum
24 for (const studentSet of benchToStudentsMap.values()) {
25 maxStudents = Math.max(maxStudents, studentSet.size);
26 }
27
28 return maxStudents;
29}
30
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the students array. This is because we iterate through the students list once to populate the dictionary, and then iterate through the dictionary values once to find the maximum. The max()
function with map(len, d.values())
takes O(m)
time where m
is the number of unique benches, but since m ≤ n
, the overall time complexity remains O(n)
.
The space complexity is O(n)
, where n
is the length of the students array. In the worst case, each student sits on a different bench, resulting in a dictionary with n
entries. Additionally, we store up to n
student IDs across all sets in the dictionary. Therefore, the total space used is proportional to n
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Not Handling Empty Input Correctly
A common mistake is forgetting to handle the edge case when the students
array is empty. If you directly call max()
on an empty sequence, Python will raise a ValueError
.
Incorrect approach:
def maxStudentsOnBench(self, students: List[List[int]]) -> int:
bench_to_students = defaultdict(set)
for student_id, bench_id in students:
bench_to_students[bench_id].add(student_id)
return max(map(len, bench_to_students.values())) # ValueError if students is empty!
Solution:
Always check for empty input first, or use max()
with a default value:
# Option 1: Explicit check (shown in original solution)
if not students:
return 0
# Option 2: Use max with default parameter
return max(map(len, bench_to_students.values()), default=0)
2. Counting Duplicate Entries Instead of Unique Students
The most critical mistake is counting each entry separately instead of tracking unique students per bench. This happens when using a list or counter instead of a set.
Incorrect approach:
def maxStudentsOnBench(self, students: List[List[int]]) -> int:
bench_counts = defaultdict(int)
for student_id, bench_id in students:
bench_counts[bench_id] += 1 # Wrong! Counts duplicates
return max(bench_counts.values()) if bench_counts else 0
This would incorrectly return 3 for input [[1,2], [1,2], [3,2]]
instead of 2.
Solution: Use a set to automatically handle uniqueness:
bench_to_students = defaultdict(set)
for student_id, bench_id in students:
bench_to_students[bench_id].add(student_id) # Set ensures uniqueness
3. Using Regular Dictionary Instead of defaultdict
Using a regular dictionary requires manual initialization of sets for new bench IDs, making the code more verbose and error-prone.
Less elegant approach:
bench_to_students = {}
for student_id, bench_id in students:
if bench_id not in bench_to_students:
bench_to_students[bench_id] = set() # Manual initialization needed
bench_to_students[bench_id].add(student_id)
Solution:
Use defaultdict(set)
for cleaner, more concise code that automatically initializes empty sets for new keys.
What does the following code do?
1def f(arr1, arr2):
2 i, j = 0, 0
3 new_arr = []
4 while i < len(arr1) and j < len(arr2):
5 if arr1[i] < arr2[j]:
6 new_arr.append(arr1[i])
7 i += 1
8 else:
9 new_arr.append(arr2[j])
10 j += 1
11 new_arr.extend(arr1[i:])
12 new_arr.extend(arr2[j:])
13 return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2 int i = 0, j = 0;
3 List<Integer> newArr = new ArrayList<>();
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.add(arr1[i]);
8 i++;
9 } else {
10 newArr.add(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.add(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.add(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
1function f(arr1, arr2) {
2 let i = 0, j = 0;
3 let newArr = [];
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.push(arr1[i]);
8 i++;
9 } else {
10 newArr.push(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.push(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.push(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
Recommended Readings
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 assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!