3769. Sort Integers by Binary Reflection
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.
How We Pick the Algorithm
Why Simulation / Basic DSA?
This problem maps to Simulation / Basic DSA through a short path in the full flowchart.
Sorting by a custom binary-reflection key is a direct simulation using a custom comparator or sort key function.
Open in FlowchartIntuition
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:
- The binary reflection value of each number.
- 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):
| Step | x (binary) | x & 1 | y before | y = y << 1 | (x & 1) | x >>= 1 |
|---|---|---|---|---|---|
| 1 | 110 | 0 | 0 | 0 | 11 |
| 2 | 11 | 1 | 0 | 1 | 1 |
| 3 | 1 | 1 | 1 | 11 (= 3) | 0 |
Result: f(6) = 3. (Binary 110 reversed is 011 → 3.)
For x = 3 (binary 11):
| Step | x (binary) | x & 1 | y before | y after | x >>= 1 |
|---|---|---|---|---|---|
| 1 | 11 | 1 | 0 | 1 | 1 |
| 2 | 1 | 1 | 1 | 11 (= 3) | 0 |
Result: f(3) = 3. (Binary 11 reversed is 11 → 3.)
For x = 5 (binary 101):
| Step | x (binary) | x & 1 | y before | y after | x >>= 1 |
|---|---|---|---|---|---|
| 1 | 101 | 1 | 0 | 1 | 10 |
| 2 | 10 | 0 | 1 | 10 (= 2) | 1 |
| 3 | 1 | 1 | 10 | 101 (= 5) | 0 |
Result: f(5) = 5. (Binary 101 reversed is 101 → 5.)
Step 2: Build the sorting key tuple (f(x), x) for each element.
Original x | f(x) | Tuple (f(x), x) |
|---|---|---|
6 | 3 | (3, 6) |
3 | 3 | (3, 3) |
5 | 5 | (5, 5) |
Step 3: Sort by the tuple key in ascending order.
Comparing the tuples:
(3, 3)and(3, 6)share the same reflection value3, so the tie is broken by the original value:3 < 6, so3comes first.(5, 5)has the largest reflection value5, 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
171class 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}
471class 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};
311/**
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}
40Time and Space Complexity
-
Time Complexity:
O(n × log n). The dominant operation is sorting the arraynums, which hasnelements and requiresO(n × log n)comparisons. For each comparison, the key functionfis involved, but Python'ssortcomputes the key once per element (Schwartzian transform), so the total key computation cost isO(n × log U), whereUis the maximum value innums(thewhileloop infiterates over the bits ofx). Since the number of bits is treated as a constant factor relative to the integer values, the overall time complexity isO(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. Herenis the length of the arraynums.
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 RoadmapWhich of the following is a min heap? 
Recommended Readings
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
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 If you prefer videos here's a video that explains recursion in a fun and easy way 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 him
Want a Structured Path to Master System Design Too? Don’t Miss This!