Facebook Pixel

3668. Restore Finishing Order

Problem Description

You are participating in a race with n participants, where each participant has a unique ID from 1 to n. After the race finishes, you have two pieces of information:

  1. order array: This array contains all participant IDs (1 to n) arranged in the sequence they finished the race. The first element represents who finished first, the second element represents who finished second, and so on.

  2. friends array: This array contains the IDs of your friends who participated in the race, sorted in increasing numerical order.

Your task is to determine the finishing order of just your friends. You need to return a new array that contains your friends' IDs arranged according to their actual finishing positions in the race.

For example, if order = [3, 1, 4, 2] (meaning participant 3 finished first, participant 1 finished second, participant 4 finished third, and participant 2 finished fourth) and friends = [1, 2], then you should return [1, 2] because among your friends, participant 1 finished before participant 2.

The solution creates a dictionary d that maps each participant ID to their finishing position index in the order array. Then it sorts the friends array based on these position indices, effectively arranging friends by their race finishing order.

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

Intuition

The key insight is that we need to extract a subset of the race results (just our friends) while preserving the original finishing order. Since the order array already tells us the complete finishing sequence, we essentially need to filter this sequence to include only our friends.

However, directly filtering the order array would require checking each participant to see if they're in the friends list, which could be inefficient. Instead, we can work backwards from the friends array.

Since we know all our friends' IDs, the challenge is determining their relative finishing positions. We can think of this as a ranking problem: each friend has a "rank" or "position" in the race, and we need to sort our friends by these ranks.

To find each friend's position quickly, we create a mapping where we can look up any participant's finishing position in O(1) time. This is done by creating a dictionary where the key is the participant ID and the value is their index in the order array (which represents their finishing position).

Once we have this position mapping, sorting the friends array becomes straightforward - we just sort by each friend's position in the race. The friend with the smallest position index finished first among the friends, the one with the next smallest position finished second among the friends, and so on.

This approach elegantly handles the problem because:

  1. We preserve the original race ordering
  2. We only return the friends' IDs
  3. The time complexity is efficient at O(n + m log m) where n is the total participants and m is the number of friends

Solution Approach

The solution uses a hash map (dictionary) combined with custom sorting to efficiently extract and order the friends' finishing positions.

Step 1: Build Position Mapping

d = {x: i for i, x in enumerate(order)}

We create a dictionary d where:

  • Key: participant ID (the value x from the order array)
  • Value: finishing position index i (0-based index representing when they finished)

For example, if order = [3, 1, 4, 2], the dictionary becomes:

  • d = {3: 0, 1: 1, 4: 2, 2: 3}
  • This means participant 3 finished at position 0 (first), participant 1 at position 1 (second), etc.

Step 2: Sort Friends by Position

return sorted(friends, key=lambda x: d[x])

We sort the friends array using a custom key function:

  • For each friend ID x in the friends array
  • The sorting key is d[x], which gives us their finishing position
  • Python's sorted() function arranges the friends in ascending order of their finishing positions

Example Walkthrough: If order = [3, 1, 4, 2] and friends = [2, 4]:

  1. Build dictionary: d = {3: 0, 1: 1, 4: 2, 2: 3}
  2. Sort friends:
    • Friend 2 has position d[2] = 3
    • Friend 4 has position d[4] = 2
    • Since 2 < 3, friend 4 finished before friend 2
  3. Return [4, 2]

Time Complexity: O(n + m log m) where n is the length of order and m is the length of friends

  • O(n) to build the dictionary
  • O(m log m) to sort the friends array

Space Complexity: O(n) for storing the position mapping dictionary

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 understand how the solution works.

Given:

  • order = [5, 2, 6, 3, 1, 4] (race finishing order)
  • friends = [1, 3, 5] (our friends' IDs)

Step 1: Build the position mapping dictionary

We create a dictionary that maps each participant ID to their finishing position:

d = {5: 0, 2: 1, 6: 2, 3: 3, 1: 4, 4: 5}

This tells us:

  • Participant 5 finished at position 0 (1st place)
  • Participant 2 finished at position 1 (2nd place)
  • Participant 3 finished at position 3 (4th place)
  • Participant 1 finished at position 4 (5th place)

Step 2: Sort friends by their race positions

Now we need to arrange our friends [1, 3, 5] based on their finishing positions:

  • Friend 1: d[1] = 4 (finished 5th overall)
  • Friend 3: d[3] = 3 (finished 4th overall)
  • Friend 5: d[5] = 0 (finished 1st overall)

When we sort by these position values (0, 3, 4), we get:

  • Position 0 → Friend 5 (finished first among all participants)
  • Position 3 → Friend 3 (finished fourth among all participants)
  • Position 4 → Friend 1 (finished fifth among all participants)

Result: [5, 3, 1]

This means among our friends, participant 5 finished first, participant 3 finished second, and participant 1 finished third.

Solution Implementation

1class Solution:
2    def recoverOrder(self, order: List[int], friends: List[int]) -> List[int]:
3        # Create a dictionary mapping each element to its index position in the original order
4        # This allows O(1) lookup of the original position for sorting
5        element_to_index = {element: index for index, element in enumerate(order)}
6      
7        # Sort the friends list based on their original positions in the order list
8        # The lambda function looks up each friend's original index for comparison
9        sorted_friends = sorted(friends, key=lambda friend: element_to_index[friend])
10      
11        return sorted_friends
12
1class Solution {
2    public int[] recoverOrder(int[] order, int[] friends) {
3        int n = order.length;
4      
5        // Create a position mapping array where positionMap[value] = index in order array
6        // This helps us determine the relative ordering of elements
7        int[] positionMap = new int[n + 1];
8        for (int i = 0; i < n; ++i) {
9            positionMap[order[i]] = i;
10        }
11      
12        // Sort the friends array based on their positions in the original order array
13        // Convert friends array to stream for functional operations
14        return Arrays.stream(friends)
15            .boxed()  // Convert int stream to Integer stream for custom sorting
16            .sorted((a, b) -> positionMap[a] - positionMap[b])  // Sort by position in original order
17            .mapToInt(Integer::intValue)  // Convert back to int stream
18            .toArray();  // Convert stream to int array
19    }
20}
21
1class Solution {
2public:
3    vector<int> recoverOrder(vector<int>& order, vector<int>& friends) {
4        int n = order.size();
5      
6        // Create a position map to store the index/position of each element in the original order
7        // positionMap[value] = index in the order array
8        vector<int> positionMap(n + 1);
9      
10        // Build the position map: for each element in order, record its position
11        for (int i = 0; i < n; ++i) {
12            positionMap[order[i]] = i;
13        }
14      
15        // Sort the friends array based on their positions in the original order
16        // Elements that appear earlier in the order array will come first
17        sort(friends.begin(), friends.end(), [&](int a, int b) {
18            return positionMap[a] < positionMap[b];
19        });
20      
21        // Return the sorted friends array
22        return friends;
23    }
24};
25
1/**
2 * Recovers the original ordering of friends based on a given order array
3 * @param order - Array representing the desired ordering sequence
4 * @param friends - Array of friend IDs to be sorted
5 * @returns Friends array sorted according to the order array
6 */
7function recoverOrder(order: number[], friends: number[]): number[] {
8    const orderLength: number = order.length;
9  
10    // Create a position mapping array where index represents the element
11    // and value represents its position in the desired order
12    const positionMap: number[] = Array(orderLength + 1).fill(0);
13  
14    // Build the position mapping: positionMap[element] = position in order
15    for (let i = 0; i < orderLength; ++i) {
16        positionMap[order[i]] = i;
17    }
18  
19    // Sort friends array based on their positions in the order array
20    // Elements appearing earlier in order array will have smaller position values
21    return friends.sort((a: number, b: number) => positionMap[a] - positionMap[b]);
22}
23

Time and Space Complexity

Time Complexity: O(n × log n), where n is the length of the friends array.

The code creates a dictionary d that maps each element in the order list to its index, which takes O(m) time where m is the length of the order array. Then it sorts the friends list using the dictionary as a key lookup. The sorting operation takes O(n × log n) time where n is the length of the friends array. Each key lookup during sorting takes O(1) time due to the hash map. Therefore, the overall time complexity is O(m + n × log n). Since typically m and n are of similar magnitude and the sorting term dominates, this simplifies to O(n × log n).

Space Complexity: O(n), where n is the length of the order array.

The dictionary d stores all elements from the order list as keys with their indices as values, requiring O(n) space. The sorted function creates a new list which also requires O(n) space for the output. Additionally, the sorting algorithm (typically Timsort in Python) uses O(log n) space for the recursion stack. Therefore, the total space complexity is O(n).

Common Pitfalls

1. Assuming Friends Array Contains Invalid IDs

A common mistake is not considering that the friends array might contain IDs that don't exist in the order array. This would cause a KeyError when trying to access d[x] for a non-existent participant.

Problem Example:

order = [3, 1, 4, 2]
friends = [1, 5]  # Participant 5 doesn't exist in the race
# This would raise: KeyError: 5

Solution: Add validation or filtering to handle invalid friend IDs:

def recoverOrder(order, friends):
    d = {x: i for i, x in enumerate(order)}
    # Filter out friends who didn't participate
    valid_friends = [f for f in friends if f in d]
    return sorted(valid_friends, key=lambda x: d[x])

2. Modifying the Original Friends Array

Some developers might try to sort the friends array in-place using friends.sort() instead of sorted(), which modifies the input array. This can cause issues if the original array is needed elsewhere or violates the expectation of not modifying input parameters.

Problem Example:

def recoverOrder(order, friends):
    d = {x: i for i, x in enumerate(order)}
    friends.sort(key=lambda x: d[x])  # Modifies original array!
    return friends

Solution: Always use sorted() to create a new sorted list:

def recoverOrder(order, friends):
    d = {x: i for i, x in enumerate(order)}
    return sorted(friends, key=lambda x: d[x])  # Creates new list

3. Incorrect Understanding of the Problem

A subtle pitfall is misunderstanding what the output should be. Some might think we need to return the positions (indices) where friends finished, rather than the friend IDs themselves in finishing order.

Wrong Interpretation:

def recoverOrder(order, friends):
    d = {x: i for i, x in enumerate(order)}
    # Returning positions instead of sorted friend IDs
    return [d[f] for f in friends]  # Wrong! Returns indices

Correct Approach:

def recoverOrder(order, friends):
    d = {x: i for i, x in enumerate(order)}
    return sorted(friends, key=lambda x: d[x])  # Returns friend IDs in order

4. Efficiency Concern with Large Datasets

While not exactly a bug, creating the full dictionary for all participants when you only need positions for a few friends can be inefficient in memory-constrained environments.

Alternative Approach for Very Large n with Small Friend Groups:

def recoverOrder(order, friends):
    friends_set = set(friends)
    result = []
    # Only iterate through order once, picking out friends
    for participant in order:
        if participant in friends_set:
            result.append(participant)
            if len(result) == len(friends):
                break  # Early termination when all friends found
    return result

This approach has O(n) time complexity but potentially better performance when the friends list is much smaller than the total participants.

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

Consider the classic dynamic programming of fibonacci numbers, what is the recurrence relation?


Recommended Readings

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

Load More