Facebook Pixel

3616. Number of Student Replacements 🔒

MediumArraySimulation
Leetcode Link

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.

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

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:

  1. Start with the first student as our initial selection (they're selected by default)
  2. For each new student, compare their rank with the current best
  3. 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 student
  • ans: counts the total number of replacements

Step-by-step implementation:

  1. Initialize: Set cur = ranks[0] (the first student is selected by default) and ans = 0 (no replacements yet)

  2. 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)
    • If no: continue to the next student
  3. 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 Evaluator

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

  1. Student with rank 5 arrives (index 0):

    • Compare: 5 < 5? No
    • No replacement occurs
    • State: cur = 5, ans = 0
  2. 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
  3. 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
  4. 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
  5. 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

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
Discover Your Strengths and Weaknesses: Take Our 5-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