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:
-
order
array: This array contains all participant IDs (1 ton
) 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. -
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.
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:
- We preserve the original race ordering
- We only return the friends' IDs
- 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 theorder
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 thefriends
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]
:
- Build dictionary:
d = {3: 0, 1: 1, 4: 2, 2: 3}
- 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
- Friend 2 has position
- 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 EvaluatorExample 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.
Consider the classic dynamic programming of fibonacci numbers, what is the recurrence relation?
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!