Facebook Pixel

2191. Sort the Jumbled Numbers

Problem Description

You have a special mapping system that changes how digits are interpreted. The mapping array tells you how to transform each digit: if mapping[i] = j, then digit i should be read as digit j.

Given this mapping system and an array of integers nums, you need to:

  1. Transform each number in nums using the mapping rules. For example, if mapping = [2,1,3,4,5,6,7,8,9,0] and you have the number 123, you would:

    • Replace digit 1 with mapping[1] = 1
    • Replace digit 2 with mapping[2] = 3
    • Replace digit 3 with mapping[3] = 4
    • Getting mapped value 134
  2. Sort the array based on these mapped values in ascending order. The original numbers in nums stay the same - you're just sorting them based on what they map to.

  3. Maintain relative order for numbers that have the same mapped value (stable sort).

Example: If mapping = [8,9,4,0,2,1,3,5,7,6] and nums = [991, 338, 38]:

  • 991 maps to 669 (9β†’6, 9β†’6, 1β†’9)
  • 338 maps to 007 = 7 (3β†’0, 3β†’0, 8β†’7)
  • 38 maps to 07 = 7 (3β†’0, 8β†’7)

Since 338 and 38 both map to 7, and 338 appears before 38 in the original array, the sorted result would be [338, 38, 991].

The solution creates tuples of (mapped_value, original_index) for each number, sorts these tuples, then reconstructs the final array using the sorted indices.

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 sort numbers based on their "translated" values while keeping the original numbers intact. This is like sorting people by their nicknames while still remembering their real names.

Since we can't directly modify the numbers in nums, we need a way to:

  1. Calculate what each number "looks like" after mapping
  2. Sort based on these mapped values
  3. Return the original numbers in the new order

The challenge is converting each digit in a number according to the mapping. For a number like 338, we need to extract each digit (3, 3, 8), map them individually (0, 0, 7), and reconstruct the mapped number (007 = 7).

To extract digits, we can repeatedly use divmod(x, 10) which gives us the last digit and the remaining number. As we process each digit from right to left, we multiply by increasing powers of 10 to rebuild the mapped number in the correct position.

For maintaining stable sort (elements with same mapped values keep their relative order), we pair each mapped value with its original index: (mapped_value, index). When Python sorts tuples, it first sorts by the first element, then by the second element for ties. Since indices naturally increase, this preserves the original order for equal mapped values.

The special case of x == 0 needs separate handling because the while loop wouldn't execute for zero (since while 0 is false), but we still need to map the single digit 0 to mapping[0].

Learn more about Sorting patterns.

Solution Approach

The solution uses custom sorting with a helper function to calculate mapped values.

Step 1: Create the mapping function f(x)

The function takes an integer and returns its mapped value:

  • Handle the special case where x == 0: directly return mapping[0]
  • For other numbers, extract digits one by one using divmod(x, 10):
    • x, v = divmod(x, 10) gives us the last digit v and remaining number x
    • Map the digit: v = mapping[v]
    • Reconstruct the mapped number by building it from right to left: y = k * v + y
    • k tracks the current position value (1, 10, 100, ...) and multiplies by 10 each iteration

Step 2: Create sortable tuples

For each element in nums, create a tuple (f(x), i) where:

  • f(x) is the mapped value of nums[i]
  • i is the original index

This is done using a generator expression: (f(x), i) for i, x in enumerate(nums)

Step 3: Sort the tuples

sorted() sorts the tuples first by mapped value, then by index. Since indices are already in ascending order, this naturally maintains stability - elements with the same mapped value keep their relative order.

Step 4: Extract the result

From the sorted array of tuples arr, extract the indices and use them to build the final result: [nums[i] for _, i in arr]

The time complexity is O(n log n) for sorting, where n is the length of nums. The space complexity is O(n) for storing the array of tuples.

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 small example with mapping = [3,1,2,5,4,0,6,7,8,9] and nums = [24, 15, 5].

Step 1: Calculate mapped values using function f(x)

For 24:

  • Extract digits: 24 β†’ 2, 4
  • Starting with rightmost digit 4: mapping[4] = 4
  • Next digit 2: mapping[2] = 2
  • Reconstruct: 2 * 10 + 4 = 24 (maps to itself!)

For 15:

  • Extract digits: 15 β†’ 1, 5
  • Starting with rightmost digit 5: mapping[5] = 0
  • Next digit 1: mapping[1] = 1
  • Reconstruct: 1 * 10 + 0 = 10

For 5:

  • Single digit: mapping[5] = 0
  • Result: 0

Step 2: Create (mapped_value, index) tuples

  • 24 at index 0 β†’ (24, 0)
  • 15 at index 1 β†’ (10, 1)
  • 5 at index 2 β†’ (0, 2)

Tuples array: [(24, 0), (10, 1), (0, 2)]

Step 3: Sort the tuples by mapped value

Sorting by first element (mapped value):

  • (0, 2) - smallest mapped value
  • (10, 1) - middle mapped value
  • (24, 0) - largest mapped value

Sorted array: [(0, 2), (10, 1), (24, 0)]

Step 4: Extract original numbers using sorted indices

From sorted tuples, take indices: 2, 1, 0

  • Index 2 β†’ nums[2] = 5
  • Index 1 β†’ nums[1] = 15
  • Index 0 β†’ nums[0] = 24

Final result: [5, 15, 24]

The original array [24, 15, 5] has been sorted to [5, 15, 24] based on their mapped values (24β†’24, 15β†’10, 5β†’0).

Solution Implementation

1class Solution:
2    def sortJumbled(self, mapping: List[int], nums: List[int]) -> List[int]:
3        def get_mapped_value(number: int) -> int:
4            """
5            Convert a number to its mapped value based on the mapping array.
6            Each digit in the number is replaced by its corresponding mapped digit.
7            """
8            # Special case: if the number is 0, directly return its mapped value
9            if number == 0:
10                return mapping[0]
11          
12            # Initialize result and position multiplier
13            mapped_result = 0
14            position_multiplier = 1
15          
16            # Process each digit from right to left
17            while number > 0:
18                # Extract the rightmost digit using divmod
19                number, digit = divmod(number, 10)
20              
21                # Get the mapped value for this digit
22                mapped_digit = mapping[digit]
23              
24                # Add the mapped digit to result at the correct position
25                mapped_result = position_multiplier * mapped_digit + mapped_result
26              
27                # Move to the next position (tens, hundreds, etc.)
28                position_multiplier *= 10
29          
30            return mapped_result
31      
32        # Create tuples of (mapped_value, original_index) for stable sorting
33        # The index ensures that elements with same mapped value maintain original order
34        mapped_with_indices = [(get_mapped_value(num), index) 
35                               for index, num in enumerate(nums)]
36      
37        # Sort by mapped values while maintaining stability
38        mapped_with_indices.sort()
39      
40        # Extract the original numbers in sorted order using the indices
41        sorted_result = [nums[index] for _, index in mapped_with_indices]
42      
43        return sorted_result
44
1class Solution {
2    // Global mapping array to store digit transformations
3    private int[] digitMapping;
4
5    /**
6     * Sorts the array based on mapped values while preserving relative order for equal mapped values
7     * @param mapping - array where mapping[i] represents what digit i maps to
8     * @param nums - array of integers to be sorted
9     * @return sorted array based on mapped values
10     */
11    public int[] sortJumbled(int[] mapping, int[] nums) {
12        this.digitMapping = mapping;
13        int length = nums.length;
14      
15        // Create a 2D array to store [mappedValue, originalIndex] pairs
16        int[][] mappedPairs = new int[length][2];
17      
18        // Calculate mapped value for each number and store with its original index
19        for (int i = 0; i < length; i++) {
20            mappedPairs[i] = new int[] {getMappedValue(nums[i]), i};
21        }
22      
23        // Sort by mapped value first, then by original index to maintain stability
24        Arrays.sort(mappedPairs, (a, b) -> {
25            if (a[0] == b[0]) {
26                return a[1] - b[1];  // If mapped values are equal, maintain original order
27            }
28            return a[0] - b[0];  // Otherwise sort by mapped value
29        });
30      
31        // Build the result array using the sorted indices
32        int[] result = new int[length];
33        for (int i = 0; i < length; i++) {
34            result[i] = nums[mappedPairs[i][1]];
35        }
36      
37        return result;
38    }
39
40    /**
41     * Converts a number to its mapped value based on digit mapping
42     * @param number - the original number to map
43     * @return the mapped value after transforming each digit
44     */
45    private int getMappedValue(int number) {
46        // Special case: if the number is 0, return its mapped value directly
47        if (number == 0) {
48            return digitMapping[0];
49        }
50      
51        int mappedValue = 0;
52        int placeValue = 1;  // Represents 1, 10, 100, 1000, etc.
53      
54        // Process each digit from right to left
55        while (number > 0) {
56            int digit = number % 10;  // Extract the rightmost digit
57            int mappedDigit = digitMapping[digit];  // Get the mapped value for this digit
58            mappedValue = mappedValue + (placeValue * mappedDigit);  // Add to result
59            placeValue *= 10;  // Move to next place value
60            number /= 10;  // Remove the processed digit
61        }
62      
63        return mappedValue;
64    }
65}
66
1class Solution {
2public:
3    vector<int> sortJumbled(vector<int>& mapping, vector<int>& nums) {
4        // Lambda function to convert a number based on the mapping
5        auto getMappedValue = [&](int num) {
6            // Special case: if the number is 0, directly return its mapped value
7            if (num == 0) {
8                return mapping[0];
9            }
10          
11            // Build the mapped number digit by digit
12            int mappedValue = 0;
13            int placeValue = 1;  // Represents 1, 10, 100, 1000, etc.
14          
15            // Process each digit from right to left
16            while (num > 0) {
17                int digit = num % 10;                    // Extract the rightmost digit
18                int mappedDigit = mapping[digit];        // Get the mapped value for this digit
19                mappedValue += placeValue * mappedDigit; // Add to result at correct position
20                placeValue *= 10;                        // Move to next place value
21                num /= 10;                                // Remove the processed digit
22            }
23          
24            return mappedValue;
25        };
26      
27        // Store pairs of (mapped value, original index) for stable sorting
28        const int n = nums.size();
29        vector<pair<int, int>> mappedPairs;
30      
31        // Create pairs of mapped values and their original indices
32        for (int i = 0; i < n; ++i) {
33            mappedPairs.emplace_back(getMappedValue(nums[i]), i);
34        }
35      
36        // Sort by mapped values (stable sort preserves relative order for equal values)
37        sort(mappedPairs.begin(), mappedPairs.end());
38      
39        // Build the result array using the sorted order
40        vector<int> result;
41        for (const auto& [mappedVal, originalIndex] : mappedPairs) {
42            result.push_back(nums[originalIndex]);
43        }
44      
45        return result;
46    }
47};
48
1/**
2 * Sorts an array of numbers based on their mapped values using a digit mapping
3 * @param mapping - Array where mapping[i] represents the mapped value for digit i
4 * @param nums - Array of numbers to be sorted
5 * @returns Sorted array based on mapped values
6 */
7function sortJumbled(mapping: number[], nums: number[]): number[] {
8    /**
9     * Converts a number to its mapped value by replacing each digit
10     * @param originalNumber - The number to be mapped
11     * @returns The mapped value of the number
12     */
13    const getMappedValue = (originalNumber: number): number => {
14        // Special case: if the number is 0, return its mapped value directly
15        if (originalNumber === 0) {
16            return mapping[0];
17        }
18      
19        let mappedValue = 0;
20        let placeValue = 1; // Represents 1, 10, 100, 1000, etc.
21      
22        // Process each digit from right to left
23        while (originalNumber > 0) {
24            // Extract the rightmost digit
25            const currentDigit = originalNumber % 10;
26          
27            // Get the mapped value for this digit
28            const mappedDigit = mapping[currentDigit];
29          
30            // Add the mapped digit at its correct position
31            mappedValue += mappedDigit * placeValue;
32          
33            // Move to the next digit position
34            placeValue *= 10;
35          
36            // Remove the rightmost digit from the number
37            originalNumber = Math.floor(originalNumber / 10);
38        }
39      
40        return mappedValue;
41    };
42  
43    // Create array of [mappedValue, originalIndex] pairs for sorting
44    const mappedPairs: number[][] = nums.map((num, index) => [getMappedValue(num), index]);
45  
46    // Sort by mapped value first, then by original index to maintain stability
47    mappedPairs.sort((a, b) => {
48        if (a[0] === b[0]) {
49            return a[1] - b[1]; // If mapped values are equal, sort by original index
50        }
51        return a[0] - b[0]; // Otherwise, sort by mapped value
52    });
53  
54    // Extract the original numbers in their new sorted order
55    return mappedPairs.map(pair => nums[pair[1]]);
56}
57

Time and Space Complexity

Time Complexity: O(n Γ— m Γ— log n) where n is the length of the array nums and m is the average number of digits in the numbers.

The time complexity breaks down as follows:

  • The function f(x) processes each digit of a number, taking O(m) time where m is the number of digits
  • We call f(x) for each of the n numbers in nums, resulting in O(n Γ— m) time
  • The sorting operation on n elements takes O(n Γ— log n) time
  • Total complexity: O(n Γ— m) + O(n Γ— log n) = O(n Γ— m Γ— log n)

However, if we consider m (the maximum number of digits) as a constant since integers have a bounded number of digits in practice, the time complexity simplifies to O(n Γ— log n).

Space Complexity: O(n)

The space complexity analysis:

  • The arr list stores tuples (f(x), i) for each element, requiring O(n) space
  • The final list comprehension creates a new list of size n, requiring O(n) space
  • The function f(x) uses O(1) auxiliary space for variables y, k, and v
  • Total space complexity: O(n)

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrectly Handling Zero

A common mistake is forgetting that 0 is a special case. When processing digits with divmod, the loop while number > 0 will never execute for number = 0, resulting in returning 0 instead of mapping[0].

Incorrect approach:

def get_mapped_value(number: int) -> int:
    mapped_result = 0
    position_multiplier = 1
  
    while number > 0:  # This loop never runs when number = 0!
        number, digit = divmod(number, 10)
        mapped_digit = mapping[digit]
        mapped_result = position_multiplier * mapped_digit + mapped_result
        position_multiplier *= 10
  
    return mapped_result  # Returns 0 instead of mapping[0]

Solution: Always check for zero as a special case before the loop.

2. Digit Reconstruction Order Error

Another pitfall is building the mapped number in the wrong order. Since we extract digits from right to left, we must carefully reconstruct the mapped value to maintain the correct digit positions.

Incorrect approach:

# Wrong: Simply appending digits leads to reversed number
mapped_result = mapped_result * 10 + mapped_digit  # This reverses the digits!

Solution: Use mapped_result = position_multiplier * mapped_digit + mapped_result to maintain correct digit positions.

3. Using Unstable Sorting

If you don't maintain the original indices when creating the sortable data structure, you might lose the relative order of elements with the same mapped value.

Incorrect approach:

# Wrong: Only sorting by mapped values loses stability
mapped_values = [get_mapped_value(num) for num in nums]
# How do we know which original number each mapped value came from?

Solution: Create tuples with both mapped values and original indices: (mapped_value, index). Python's sort is stable and will preserve the original order for equal mapped values.

4. String Conversion Inefficiency

Some might be tempted to convert numbers to strings for digit manipulation, which is less efficient and can introduce edge cases.

Less optimal approach:

def get_mapped_value(number: int) -> int:
    num_str = str(number)
    mapped_str = ''.join(str(mapping[int(digit)]) for digit in num_str)
    return int(mapped_str)  # Potential issues with leading zeros

This approach has problems:

  • Less efficient due to string operations
  • May incorrectly handle cases where mapped digits create leading zeros (e.g., if mapping[3] = 0, then 38 might become "08" which converts to 8 instead of maintaining the structure)

Solution: Stick with mathematical operations using divmod for better performance and correctness.

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

Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?


Recommended Readings

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

Load More