Skip to main content
Back to problems
#3188
Hard Database

Find top scoring students ii

Database
40.0% acceptance
Mar 31, 2026
8
8

No description available.

Solution

Pandas
Time O(1)
Space O(1)
LeetCode
solution.pandas
# Table: students
# 
# +-------------+----------+
# | Column Name | Type     |
# +-------------+----------+
# | student_id  | int      |
# | name        | varchar  |
# | major       | varchar  |
# +-------------+----------+
# student_id is the primary key for this table.
# Each row contains the student ID, student name, and their major.
# 
# Table: courses
# 
# +-------------+-------------------+
# | Column Name | Type              |
# +-------------+-------------------+
# | course_id   | int               |
# | name        | varchar           |
# | credits     | int               |
# | major       | varchar           |
# | mandatory   | enum              |
# +-------------+-------------------+
# course_id is the primary key for this table.
# mandatory is an enum type of ('Yes', 'No').
# Each row contains the course ID, course name, credits, major it belongs to, and whether the course is mandatory.
# 
# Table: enrollments
# 
# +-------------+----------+
# | Column Name | Type     |
# +-------------+----------+
# | student_id  | int      |
# | course_id   | int      |
# | semester    | varchar  |
# | grade       | varchar  |
# | GPA         | decimal  |
# +-------------+----------+
# (student_id, course_id, semester) is the primary key (combination of columns with unique values) for this table.
# Each row contains the student ID, course ID, semester, and grade received.
# 
# Write a solution to find the students who meet the following criteria:
# 
# Have taken all mandatory courses and at least two elective courses offered in their major.
# 
# Achieved a grade of A in all mandatory courses and at least B in elective courses.
# 
# Maintained an average GPA of at least 2.5 across all their courses (including those outside their major).
# 
# Return the result table ordered by student_id in ascending order.
#
# Example 1:
# Input:
# students table:
# +------------+------------------+------------------+
# | student_id | name             | major            |
# +------------+------------------+------------------+
# | 1          | Alice            | Computer Science |
# | 2          | Bob              | Computer Science |
# | 3          | Charlie          | Mathematics      |
# | 4          | David            | Mathematics      |
# +------------+------------------+------------------+
# courses table:
# +-----------+-------------------+---------+------------------+----------+
# | course_id | name              | credits | major            | mandatory|
# +-----------+-------------------+---------+------------------+----------+
# | 101       | Algorithms        | 3       | Computer Science | yes      |
# | 102       | Data Structures   | 3       | Computer Science | yes      |
# | 103       | Calculus          | 4       | Mathematics      | yes      |
# | 104       | Linear Algebra    | 4       | Mathematics      | yes      |
# | 105       | Machine Learning  | 3       | Computer Science | no       |
# | 106       | Probability       | 3       | Mathematics      | no       |
# | 107       | Operating Systems | 3       | Computer Science | no       |
# | 108       | Statistics        | 3       | Mathematics      | no       |
# +-----------+-------------------+---------+------------------+----------+
# enrollments table:
# +------------+-----------+-------------+-------+-----+
# | student_id | course_id | semester    | grade | GPA |
# +------------+-----------+-------------+-------+-----+
# | 1          | 101       | Fall 2023   | A     | 4.0 |
# | 1          | 102       | Spring 2023 | A     | 4.0 |
# | 1          | 105       | Spring 2023 | A     | 4.0 |
# | 1          | 107       | Fall 2023   | B     | 3.5 |
# | 2          | 101       | Fall 2023   | A     | 4.0 |
# | 2          | 102       | Spring 2023 | B     | 3.0 |
# | 3          | 103       | Fall 2023   | A     | 4.0 |
# | 3          | 104       | Spring 2023 | A     | 4.0 |
# | 3          | 106       | Spring 2023 | A     | 4.0 |
# | 3          | 108       | Fall 2023   | B     | 3.5 |
# | 4          | 103       | Fall 2023   | B     | 3.0 |
# | 4          | 104       | Spring 2023 | B     | 3.0 |
# +------------+-----------+-------------+-------+-----+
# Output:
# +------------+
# | student_id |
# +------------+
# | 1          |
# | 3          |
# +------------+
# Explanation:
# Alice (student_id 1) is a Computer Science major and has taken both Algorithms and Data Structures, receiving an A in both. She has also taken Machine Learning and Operating Systems as electives, receiving an A and B respectively.
# Bob (student_id 2) is a Computer Science major but did not receive an A in all required courses.
# Charlie (student_id 3) is a Mathematics major and has taken both Calculus and Linear Algebra, receiving an A in both. He has also taken Probability and Statistics as electives, receiving an A and B respectively.
# David (student_id 4) is a Mathematics major but did not receive an A in all required courses.
# Note: Output table is ordered by student_id in ascending order.

import pandas as pd

def find_top_scoring_students(students: pd.DataFrame, courses: pd.DataFrame, enrollments: pd.DataFrame) -> pd.DataFrame:
  # Get mandatory and elective courses per major
  mandatory = courses[courses['mandatory'].str.lower() == 'yes']
  elective = courses[courses['mandatory'].str.lower() == 'no']
  # Join students with their major's mandatory courses
  student_mandatory = students.merge(mandatory, on='major')[['student_id', 'course_id']]
  mandatory_count = student_mandatory.groupby('student_id')['course_id'].nunique().reset_index(name='mandatory_required')
  # Check mandatory: all A
  a_mandatory = enrollments[enrollments['grade'] == 'A'].merge(student_mandatory, on=['student_id', 'course_id'])
  a_mandatory_count = a_mandatory.groupby('student_id')['course_id'].nunique().reset_index(name='mandatory_done')
  # Check elective: grade A or B, at least 2
  student_elective = students.merge(elective, on='major')[['student_id', 'course_id']]
  ab_elective = enrollments[enrollments['grade'].isin(['A', 'B'])].merge(student_elective, on=['student_id', 'course_id'])
  ab_elective_count = ab_elective.groupby('student_id')['course_id'].nunique().reset_index(name='elective_done')
  # Average GPA >= 2.5 across all courses
  avg_gpa = enrollments.groupby('student_id')['GPA'].mean().reset_index(name='avg_gpa')
  # Combine
  result = students[['student_id']].merge(mandatory_count, on='student_id', how='left').fillna(0)
  result = result.merge(a_mandatory_count, on='student_id', how='left').fillna(0)
  result = result.merge(ab_elective_count, on='student_id', how='left').fillna(0)
  result = result.merge(avg_gpa, on='student_id', how='left').fillna(0)
  result = result[
    (result['mandatory_required'] == result['mandatory_done']) &
    (result['mandatory_required'] > 0) &
    (result['elective_done'] >= 2) &
    (result['avg_gpa'] >= 2.5)
  ][['student_id']]
  return result.sort_values('student_id').reset_index(drop=True)