Facebook Pixel

3450. Maximum Students on a Single Bench 🔒

EasyArrayHash Table
Leetcode Link

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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. Initialize the data structure: We create a defaultdict(set) called d. 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
  2. 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 the student_id to the set corresponding to bench_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
  3. 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 the len function to each set, giving us the count of unique students per bench
    • max() returns the largest count among all benches
  4. 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 Evaluator

Example 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 set

    • d = {2: {1}}
  • Process [3, 2]: Add student 3 to bench 2's set

    • d = {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 set

    • d = {2: {1, 3}, 5: {4}}
  • Process [5, 5]: Add student 5 to bench 5's set

    • d = {2: {1, 3}, 5: {4, 5}}
  • Process [1, 5]: Add student 1 to bench 5's set

    • d = {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.

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More