Facebook Pixel

3769. Sort Integers by Binary Reflection

EasyArraySorting
LeetCode ↗

Problem Description

You are given an integer array nums.

The binary reflection of a positive integer is defined as follows: take the integer's binary representation (without any leading zeros), reverse the order of its binary digits, and then interpret the reversed binary string as a decimal number.

For example, if a number is 6, its binary representation is 110. Reversing the digits gives 011, which is 11 in binary (leading zeros are dropped), and that equals 3 in decimal. So the binary reflection of 6 is 3.

Your task is to sort the array in ascending order based on the binary reflection value of each element. If two different numbers happen to have the same binary reflection value, the smaller original number should appear first in the result.

Return the resulting sorted array.

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

How We Pick the Algorithm

Why Simulation / Basic DSA?

This problem maps to Simulation / Basic DSA through a short path in the full flowchart.

JustsimulatetheyesCustomsortingrule?yesSimulation /Basic DSA

Sorting by a custom binary-reflection key is a direct simulation using a custom comparator or sort key function.

Open in Flowchart

Intuition

The problem asks us to sort the array by a custom rule, so the natural idea is to use a custom sorting key for each element.

The key insight is that the sorting order is determined by two things, in order of priority:

  1. The binary reflection value of each number.
  2. When two numbers share the same reflection value, the original number itself (smaller first).

This naturally maps to sorting by the tuple (reflection(x), x). By placing the reflection value first and the original value second, the comparison automatically falls back to the original value whenever two reflection values are equal.

The remaining challenge is computing the binary reflection. To reverse the binary digits of x, we can process x bit by bit. At each step, we extract the lowest bit of x using x & 1, then append it to a result y by shifting y left and adding the bit (y = y << 1 | (x & 1)). After that, we shift x right (x >>= 1) to move on to the next bit. Repeating this until x becomes 0 builds up the reversed binary number, and any trailing zeros that were leading zeros in the reflection are automatically ignored since we never start building y with them as high bits.

Once we have this reflection function, we simply sort nums using the tuple key and return the result.

Pattern Learn more about Sorting patterns.

Solution Approach

Solution 1: Custom Sorting

We define a function f(x) to calculate the binary reflection value of integer x. Specifically, we continuously extract the lowest bit of x and add it to the end of the result y until x becomes 0.

Inside f(x), we start with y = 0. While x is not 0, we perform y = y << 1 | (x & 1): this shifts y left by one position to make room, then sets the new lowest bit to the current lowest bit of x (obtained via x & 1). After that, we do x >>= 1 to discard the bit we just processed and move on to the next one. This effectively reads the bits of x from low to high and writes them into y from high to low, producing the reversed binary number. Leading zeros in the reflection are handled naturally, since y only starts accumulating once a 1 bit appears at its high end.

Then, we sort the array nums with the sorting key being the tuple (f(x), x) of each element's binary reflection value and original value. This ensures that when two elements have the same binary reflection value, the smaller original value will be placed first.

Finally, we return the sorted array.

In terms of complexity, let n be the length of nums and M be the maximum value in the array. Computing f(x) takes O(log M) time per element, and sorting takes O(n \log n) comparisons. Therefore, the overall time complexity is O(n \times (\log n + \log M)), and the space complexity is O(\log n) for the sorting overhead (ignoring the in-place sort's own auxiliary usage).

Example Walkthrough

Let's trace through a small example with nums = [6, 3, 5].

Step 1: Compute the binary reflection f(x) for each element.

We use the bit-by-bit process y = y << 1 | (x & 1), then x >>= 1, repeating until x becomes 0.

For x = 6 (binary 110):

Stepx (binary)x & 1y beforey = y << 1 | (x & 1)x >>= 1
111000011
2111011
311111 (= 3)0

Result: f(6) = 3. (Binary 110 reversed is 0113.)

For x = 3 (binary 11):

Stepx (binary)x & 1y beforey afterx >>= 1
1111011
211111 (= 3)0

Result: f(3) = 3. (Binary 11 reversed is 113.)

For x = 5 (binary 101):

Stepx (binary)x & 1y beforey afterx >>= 1
110110110
2100110 (= 2)1
31110101 (= 5)0

Result: f(5) = 5. (Binary 101 reversed is 1015.)

Step 2: Build the sorting key tuple (f(x), x) for each element.

Original xf(x)Tuple (f(x), x)
63(3, 6)
33(3, 3)
55(5, 5)

Step 3: Sort by the tuple key in ascending order.

Comparing the tuples:

  • (3, 3) and (3, 6) share the same reflection value 3, so the tie is broken by the original value: 3 < 6, so 3 comes first.
  • (5, 5) has the largest reflection value 5, so it comes last.

Sorted order of tuples: (3, 3), (3, 6), (5, 5).

Step 4: Extract the original values.

The resulting sorted array is [3, 6, 5].

This confirms the approach: the (f(x), x) tuple key sorts primarily by binary reflection, and automatically falls back to the original number when reflection values are tied — exactly placing 3 before 6 since they both reflect to 3.

Solution Implementation

1class Solution:
2    def sortByReflection(self, nums: List[int]) -> List[int]:
3        def reverse_bits(num: int) -> int:
4            # Reverse the significant bits of num.
5            # Example: 6 (binary 110) -> 011 = 3
6            result = 0
7            while num:
8                # Shift result left to make room, then append the lowest bit of num.
9                result = result << 1 | (num & 1)
10                # Drop the lowest bit of num.
11                num >>= 1
12            return result
13
14        # Sort primarily by the bit-reversed value, then by the original value as a tie-breaker.
15        nums.sort(key=lambda x: (reverse_bits(x), x))
16        return nums
17
1class Solution {
2    public int[] sortByReflection(int[] nums) {
3        int n = nums.length;
4
5        // Use a boxed Integer array so we can supply a custom Comparator
6        Integer[] boxed = new Integer[n];
7        Arrays.setAll(boxed, i -> nums[i]);
8
9        // Sort by the bit-reversed value first; if equal, sort by the original value
10        Arrays.sort(boxed, (first, second) -> {
11            int reflectedFirst = f(first);
12            int reflectedSecond = f(second);
13            if (reflectedFirst != reflectedSecond) {
14                return Integer.compare(reflectedFirst, reflectedSecond);
15            }
16            return Integer.compare(first, second);
17        });
18
19        // Copy the sorted boxed values back into the primitive result array
20        for (int i = 0; i < n; i++) {
21            nums[i] = boxed[i];
22        }
23        return nums;
24    }
25
26    /**
27     * Reflects (reverses) the significant bits of the given value.
28     * It reads bits from least-significant to most-significant and
29     * rebuilds them in reverse order, stopping at the highest set bit.
30     *
31     * Example: 6 (110) -> 3 (011)
32     *
33     * @param value the input integer
34     * @return the value formed by reversing its significant bits
35     */
36    private int f(int value) {
37        int reflected = 0;
38        while (value != 0) {
39            // Shift the result left and append the current lowest bit of value
40            reflected = (reflected << 1) | (value & 1);
41            // Drop the lowest bit of value
42            value >>= 1;
43        }
44        return reflected;
45    }
46}
47
1class Solution {
2public:
3    vector<int> sortByReflection(vector<int>& nums) {
4        // Reflect (reverse) the bits of 'value' up to its highest set bit.
5        // Example: 6 (110) -> 3 (011); 4 (100) -> 1 (001).
6        auto reflectBits = [](int value) {
7            int reflected = 0;
8            while (value) {
9                // Shift the result left and append the current lowest bit.
10                reflected = (reflected << 1) | (value & 1);
11                value >>= 1;
12            }
13            return reflected;
14        };
15
16        // Sort by the bit-reflected value in ascending order.
17        // When two reflected values are equal, fall back to comparing
18        // the original values to keep the ordering deterministic.
19        sort(nums.begin(), nums.end(), [&](int lhs, int rhs) {
20            int reflectedLhs = reflectBits(lhs);
21            int reflectedRhs = reflectBits(rhs);
22            if (reflectedLhs != reflectedRhs) {
23                return reflectedLhs < reflectedRhs;
24            }
25            return lhs < rhs;
26        });
27
28        return nums;
29    }
30};
31
1/**
2 * Sorts the array based on the "reflection" (bit reversal) of each number.
3 * Numbers are ordered primarily by their reflected bit pattern,
4 * and ties are broken by the original numeric value.
5 *
6 * @param nums - The array of non-negative integers to sort.
7 * @returns The array sorted by reflection value, then by original value.
8 */
9function sortByReflection(nums: number[]): number[] {
10    /**
11     * Computes the reflection of a number by reversing the order
12     * of its significant bits (from the most significant set bit downward).
13     *
14     * @param value - The number whose bits are to be reversed.
15     * @returns The integer formed by reversing the significant bits.
16     */
17    const reflect = (value: number): number => {
18        let reflected = 0;
19        // Process each bit from least significant to most significant.
20        for (; value; value >>= 1) {
21            // Shift the result left and append the current lowest bit.
22            reflected = (reflected << 1) | (value & 1);
23        }
24        return reflected;
25    };
26
27    nums.sort((a: number, b: number): number => {
28        const reflectA = reflect(a);
29        const reflectB = reflect(b);
30        // Primary comparison: by reflected bit value.
31        if (reflectA !== reflectB) {
32            return reflectA - reflectB;
33        }
34        // Secondary comparison: by original value to break ties.
35        return a - b;
36    });
37
38    return nums;
39}
40

Time and Space Complexity

  • Time Complexity: O(n × log n). The dominant operation is sorting the array nums, which has n elements and requires O(n × log n) comparisons. For each comparison, the key function f is involved, but Python's sort computes the key once per element (Schwartzian transform), so the total key computation cost is O(n × log U), where U is the maximum value in nums (the while loop in f iterates over the bits of x). Since the number of bits is treated as a constant factor relative to the integer values, the overall time complexity is O(n × log n).

  • Space Complexity: O(log n). Aside from the storage for the keys, the additional space is primarily consumed by the sorting algorithm's recursion or temporary buffers. Here n is the length of the array nums.

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

Common Pitfalls

Pitfall 1: Reversing a Fixed-Width Bit Representation (e.g., 32 bits)

A very common mistake is to treat the binary reflection like the classic "reverse bits of a 32-bit integer" problem. In that classic problem, you reverse all 32 bits, including leading zeros. However, this problem explicitly states that the binary representation should be taken without leading zeros, and leading zeros produced by the reversal should also be dropped.

Incorrect approach:

def reverse_bits_wrong(num: int) -> int:
    result = 0
    for _ in range(32):  # WRONG: assumes a fixed 32-bit width
        result = (result << 1) | (num & 1)
        num >>= 1
    return result

For num = 6 (binary 110), this would pad to 00000000000000000000000000000110, reverse it to 01100000000000000000000000000000, and produce a huge number instead of the expected 3.

Solution: Loop only while num still has bits remaining (while num:), so the reversal is bounded by the number's own significant bits. This matches the definition where both the input's leading zeros and the output's leading zeros are dropped.

def reverse_bits(num: int) -> int:
    result = 0
    while num:
        result = result << 1 | (num & 1)
        num >>= 1
    return result

Pitfall 2: Forgetting the Tie-Breaker Rule

The problem requires that when two different numbers share the same binary reflection value, the smaller original number comes first. If you sort only by the reflection value, the relative order of ties depends on Python's stable sort preserving the input order, which is not guaranteed to be ascending by original value.

Incorrect approach:

nums.sort(key=lambda x: reverse_bits(x))  # WRONG: no tie-breaker

For example, 2 (binary 10 → reflection 01 = 1) and 1 (binary 1 → reflection 1) both reflect to 1. If the input is [2, 1], sorting by reflection alone keeps [2, 1], but the correct answer is [1, 2].

Solution: Use the tuple (reverse_bits(x), x) as the sort key so ties are broken by the original value.

nums.sort(key=lambda x: (reverse_bits(x), x))

Pitfall 3: Recomputing the Reflection During Comparisons

If you implement a comparator (e.g., via functools.cmp_to_key) instead of a key function, reverse_bits may be recomputed many times for the same element across multiple comparisons, degrading performance.

Solution: Use a key function (as in the provided solution). Python computes the key exactly once per element (the decorate-sort-undecorate pattern), giving an overall O(n × (log n + log M)) time rather than recomputing reflections on every comparison.

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

Which of the following is a min heap?


Recommended Readings

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

Load More