3616. Number of Student Replacements 🔒
Problem Description
You have an array ranks
where ranks[i]
represents the rank of the i-th student arriving in order. A smaller rank number means a better rank (for example, rank 1 is better than rank 5).
Initially, the first student to arrive is automatically selected.
A replacement happens when a new student arrives with a strictly better rank (smaller number) than the currently selected student. When this happens, the new student replaces the currently selected one.
Your task is to count how many times a replacement occurs as students arrive one by one.
For example, if ranks = [3, 1, 4, 2]
:
- Student with rank 3 arrives first and is selected (no replacement)
- Student with rank 1 arrives and replaces the current selection since 1 < 3 (1 replacement)
- Student with rank 4 arrives but doesn't replace since 4 > 1 (no replacement)
- Student with rank 2 arrives but doesn't replace since 2 > 1 (no replacement)
- Total replacements = 1
The solution tracks the current best rank using variable cur
, starting with the first student's rank. For each subsequent student, if their rank is better (smaller) than cur
, we update cur
and increment our replacement counter. The final count is returned as the answer.
Intuition
The key insight is that we only care about tracking the best (smallest) rank seen so far. Since students arrive in order and we can only replace the current selection with someone better, we need to maintain a running minimum.
Think of it like a competition where the current champion can only be dethroned by someone with a better score. Each time we see a new student, we ask: "Is this student's rank better than our current champion?" If yes, we have a new champion (replacement occurs). If no, the current champion stays.
This naturally leads to a single-pass solution where we:
- Start with the first student as our initial selection (they're selected by default)
- For each new student, compare their rank with the current best
- If they have a better rank (smaller number), they become the new selection and we count this as a replacement
The pattern here is essentially finding how many times the minimum value updates as we traverse the array from left to right. Each update represents a replacement event. This is why we only need to track the current minimum (cur
) and count how many times it changes (ans
).
Since we process students in arrival order and only make decisions based on the current best rank, we don't need to look ahead or store previous values - just maintain the running minimum and count the updates.
Solution Approach
We implement a simulation approach that processes students one by one in their arrival order.
The algorithm uses two variables:
cur
: tracks the rank of the currently selected studentans
: counts the total number of replacements
Step-by-step implementation:
-
Initialize: Set
cur = ranks[0]
(the first student is selected by default) andans = 0
(no replacements yet) -
Iterate through all students: For each student's rank
x
in the array:- Check if
x < cur
(is this student's rank better than the current selection?) - If yes:
- Update
cur = x
(this student becomes the new selection) - Increment
ans += 1
(count this replacement)
- Update
- If no: continue to the next student
- Check if
-
Return the result: After processing all students, return
ans
as the total number of replacements
The code implementation:
class Solution:
def totalReplacements(self, ranks: List[int]) -> int:
ans, cur = 0, ranks[0]
for x in ranks:
if x < cur:
cur = x
ans += 1
return ans
Time Complexity: O(n)
where n
is the length of the ranks array, as we make a single pass through the array.
Space Complexity: O(1)
as we only use two variables regardless of input size.
The beauty of this solution is its simplicity - we're essentially tracking the running minimum and counting how many times it changes throughout the traversal.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's trace through the algorithm with ranks = [5, 2, 6, 1, 3]
:
Initial Setup:
cur = ranks[0] = 5
(first student with rank 5 is selected)ans = 0
(no replacements yet)
Processing each student:
-
Student with rank 5 arrives (index 0):
- Compare:
5 < 5
? No - No replacement occurs
- State:
cur = 5
,ans = 0
- Compare:
-
Student with rank 2 arrives (index 1):
- Compare:
2 < 5
? Yes! - Replacement occurs: student with rank 2 replaces rank 5
- Update:
cur = 2
,ans = 1
- Compare:
-
Student with rank 6 arrives (index 2):
- Compare:
6 < 2
? No - No replacement (rank 6 is worse than rank 2)
- State:
cur = 2
,ans = 1
- Compare:
-
Student with rank 1 arrives (index 3):
- Compare:
1 < 2
? Yes! - Replacement occurs: student with rank 1 replaces rank 2
- Update:
cur = 1
,ans = 2
- Compare:
-
Student with rank 3 arrives (index 4):
- Compare:
3 < 1
? No - No replacement (rank 3 is worse than rank 1)
- State:
cur = 1
,ans = 2
- Compare:
Final Result: Return ans = 2
The algorithm correctly identifies that 2 replacements occurred:
- When rank 2 replaced rank 5
- When rank 1 replaced rank 2
Solution Implementation
1class Solution:
2 def totalReplacements(self, ranks: List[int]) -> int:
3 # Initialize counter for replacements and current minimum value
4 replacement_count = 0
5 current_min = ranks[0]
6
7 # Iterate through all ranks to find decreasing values
8 for rank_value in ranks:
9 # Check if current value is smaller than the tracked minimum
10 if rank_value < current_min:
11 # Update the minimum value
12 current_min = rank_value
13 # Increment replacement counter
14 replacement_count += 1
15
16 # Return total number of replacements (times a new minimum was found)
17 return replacement_count
18
1class Solution {
2 public int totalReplacements(int[] ranks) {
3 // Initialize the count of replacements
4 int replacementCount = 0;
5
6 // Track the current minimum value, starting with the first element
7 int currentMinimum = ranks[0];
8
9 // Iterate through each element in the array
10 for (int element : ranks) {
11 // If we find an element smaller than our current minimum
12 if (element < currentMinimum) {
13 // Update the current minimum to this smaller value
14 currentMinimum = element;
15 // Increment the replacement count
16 replacementCount++;
17 }
18 }
19
20 // Return the total number of replacements made
21 return replacementCount;
22 }
23}
24
1class Solution {
2public:
3 int totalReplacements(vector<int>& ranks) {
4 // Initialize the count of replacements
5 int replacementCount = 0;
6
7 // Track the current minimum value, starting with the first element
8 int currentMinimum = ranks[0];
9
10 // Iterate through each element in the array
11 for (int value : ranks) {
12 // If we find a smaller value than our current minimum
13 if (value < currentMinimum) {
14 // Update the current minimum to this new smaller value
15 currentMinimum = value;
16 // Increment the replacement count
17 ++replacementCount;
18 }
19 }
20
21 // Return the total number of replacements made
22 return replacementCount;
23 }
24};
25
1/**
2 * Calculates the total number of replacements where a smaller value replaces the current minimum.
3 * @param ranks - Array of numbers to process
4 * @returns The count of replacements made
5 */
6function totalReplacements(ranks: number[]): number {
7 // Initialize the answer counter and current minimum value
8 let answer: number = 0;
9 let currentMinimum: number = ranks[0];
10
11 // Iterate through each element in the ranks array
12 for (const value of ranks) {
13 // Check if current value is smaller than the current minimum
14 if (value < currentMinimum) {
15 // Update the current minimum to the new smaller value
16 currentMinimum = value;
17 // Increment the replacement counter
18 answer++;
19 }
20 }
21
22 // Return the total number of replacements
23 return answer;
24}
25
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the ranks
list. The algorithm iterates through the list exactly once with a single for loop, performing constant-time operations (comparisons and assignments) for each element.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space for the variables ans
and cur
, regardless of the input size. No additional data structures that scale with the input are created.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Including the First Student in the Replacement Count
The Mistake: Some might incorrectly count the first student's arrival as a replacement:
# INCORRECT Implementation
def totalReplacements(self, ranks: List[int]) -> int:
replacement_count = 0
current_min = float('inf') # Starting with infinity
for rank_value in ranks:
if rank_value < current_min:
current_min = rank_value
replacement_count += 1 # This counts the first student incorrectly!
return replacement_count
This would return 2 for ranks = [3, 1, 4, 2]
instead of 1, because it counts the initial selection of student with rank 3 as a replacement.
The Fix: Start with the first student as the initial selection (not counting it as a replacement):
# CORRECT Implementation
def totalReplacements(self, ranks: List[int]) -> int:
replacement_count = 0
current_min = ranks[0] # First student is selected by default
for rank_value in ranks[1:]: # Start from second student
if rank_value < current_min:
current_min = rank_value
replacement_count += 1
return replacement_count
Pitfall 2: Using Wrong Comparison Operator
The Mistake: Using <=
instead of <
when checking for better rank:
# INCORRECT - counts equal ranks as replacements if rank_value <= current_min: current_min = rank_value replacement_count += 1
This violates the "strictly better" requirement. A student with the same rank shouldn't trigger a replacement.
The Fix: Always use strict inequality (<
) to ensure only strictly better ranks cause replacements.
Pitfall 3: Not Handling Edge Cases
The Mistake: Forgetting to handle arrays with only one element or empty arrays:
# Potential issues with edge cases
def totalReplacements(self, ranks: List[int]) -> int:
current_min = ranks[0] # IndexError if ranks is empty
# ... rest of code
The Fix: Add proper edge case handling:
def totalReplacements(self, ranks: List[int]) -> int:
if not ranks or len(ranks) == 1:
return 0
replacement_count = 0
current_min = ranks[0]
for rank_value in ranks[1:]:
if rank_value < current_min:
current_min = rank_value
replacement_count += 1
return replacement_count
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!