Problem
Link to the original HackerRank problem
Given the names and grades for each student in a class of
N
students, store them in a nested list and print the name(s) of any student(s) having the second lowest grade.Note: If there are mutliple students with the second lowest grade, order their names aphabetically and print each name on a new line.
Example
records = [["chi", 20.0], ["beta", 50.0], ["alpha", 50.0]]
The ordered list of scores is
[20.0, 50.0]
, so the second lowest score is50.0
.There are tow students with that score:
["beta", "alpha"]
.Ordered alphabetically, the names are printed as:
alpha beta
Input Format
The first line contains an integer,
N
, the number of students.The
2N
subsequent lines describe each student over2
lines.
- The first line contains a student’s name.
-100 <= A[i] <= 100
Constraints
2 <= N <= 5
- There will always be one ore more students having the second lowest grade.
Output Format
Print the name(s) of any student(s) having the second lowest grade in.
If there are multiple students, order their names alphabetically and print each one on a new line.
Sample Output 0
55 Harry 37.21 Berry 37.21 Tina 37.2 Akriti 41 Harsh 39
Sample Output 0
Berry
Explanation 0
There are
5
students in this class whose names and grades are assembled to build the following list:python students = [['Harry', 37.21], ['Berry', 37.21], ['Tina', 37.2], ['Akriti', 41], ['Harsh', 39]]
The lowest grade of
37.2
belongs to Tina.The second lowest grade of
37.21
belongs to both Harry and Berry, so we order their names alphabetically and print each name of a new line.
Code
Starter
if __name__ == '__main__':
for _ in range(int(input())):
name = input()
score = float(input())
Solutions
Naive and Terse
Implementation
A first naive, yet simple and terse solution is to simply:
- First, store the names of the student by their grades in a dictionary
- Then, sort the keys (i.e., grades) of that dictionary
- Which allows to get the second-lowest grade key via index
- Use that key to get the associated names in the dictionary
- Print the names in alphabetical order
To make the implementation even terser, I am using the defaultdict
below which initializes a default value using the passed factory function, here, list
(empty list) when a new key that hasn’t been already added is being looked up to then append the relevant name (value) relative to its grade.
from collections import defaultdict
if __name__ == '__main__':
n = int(input())
students_grade_to_names = defaultdict(list)
for _ in range(n):
name = input()
grade = float(input())
students_grade_to_names[grade].append(name)
second_lowest_grade = sorted(students_grade_to_names.keys())[1]
snd_lowest_grade_names = students_grade_to_names[second_lowest_grade]
print(*sorted(snd_lowest_grade_names), sep='\n')
Complexity
Time
- Worst Case:
O(n log n)
- Occurs when all grades are unique (
k = n
). - Sorting the keys takes
O(n log n)
.
- Occurs when all grades are unique (
- Best Case:
O(n)
- Only two unique grades exist (
k = 2
). - Sorting becomes
O(1)
.
- Only two unique grades exist (
- Average Case:
O(n + k log k)
- Depends on the number of unique grades (
k
). - Building the dictionary is
O(n)
, and sorting isO(k log k)
.
- Depends on the number of unique grades (
Space
- Worst | Average | Best Case:
O(n)
- Stores all student names and grades in a dictionary.
Verbose
Implementation
if __name__ == '__main__':
n = int(input())
fst_lowest_grade = float('inf')
snd_lowest_grade = float('inf')
fst_lowest_grade_names = []
snd_lowest_grade_names = []
for _ in range(n):
name = input()
grade = float(input())
if grade < fst_lowest_grade:
snd_lowest_grade = fst_lowest_grade
snd_lowest_grade_names = fst_lowest_grade_names
fst_lowest_grade = grade
fst_lowest_grade_names = [name]
elif grade == fst_lowest_grade:
fst_lowest_grade_names.append(name)
elif grade < snd_lowest_grade:
snd_lowest_grade = grade
snd_lowest_grade_names = [name]
elif grade == snd_lowest_grade:
snd_lowest_grade_names.append(name)
print(*sorted(snd_lowest_grade_names), sep='\n')
Complexity
Time
- Worst | Average | Best Case:
O(n)
- Each student is processed in constant time (
O(1)
) per iteration. - The loop runs
n
times, leading toO(n)
total time.
- Each student is processed in constant time (
Space
- Worst Case:
O(n)
- Occurs when all students except one share the second-lowest grade (e.g.,
snd_lowest_grade_names
stores nearly all names).
- Occurs when all students except one share the second-lowest grade (e.g.,
- Best Case:
O(1)
- Only
1
student has the second-lowest grade. - However, in practice, space depends on the number of students with the first/second-lowest grades (
O(m)
, wherem
is the count of such students).
- Only