A clear explanation of checking whether the digits of a number can be reordered to form a power of two using digit frequency signatures.
Problem Restatement
We are given a positive integer n.
We may reorder its digits in any way.
The reordered number:
- Cannot have leading zeroes.
- Must use exactly the same digits.
We need to return True if some reordering forms a power of two.
Otherwise, return False.
Input and Output
| Item | Meaning |
|---|---|
| Input | Positive integer n |
| Output | True if some digit reordering forms a power of two |
| Constraint | No leading zeroes allowed |
Function shape:
class Solution:
def reorderedPowerOf2(self, n: int) -> bool:
...Examples
Example 1:
n = 1The number 1 is already a power of two:
2^0 = 1So the answer is:
TrueExample 2:
n = 10Possible reorderings:
10
01The second form is invalid because of the leading zero.
10 is not a power of two.
So the answer is:
FalseExample 3:
n = 46Reordering the digits gives:
64and:
64 = 2^6So the answer is:
TrueFirst Thought: Try Every Permutation
One direct approach is:
- Generate every permutation of the digits.
- Ignore permutations with leading zeroes.
- Convert each permutation into an integer.
- Check whether it is a power of two.
This works for small numbers, but the number of permutations grows very quickly.
If there are d digits, there can be up to:
d!permutations.
We need something simpler.
Key Insight
Two numbers can be reordered into each other exactly when they contain the same digits with the same frequencies.
For example:
| Number | Digit counts |
|---|---|
128 | one 1, one 2, one 8 |
821 | one 1, one 2, one 8 |
So instead of generating permutations, we compare digit frequency signatures.
The plan:
- Compute the digit signature of
n. - Generate all powers of two within the valid range.
- If any power of two has the same digit signature, return
True.
Since:
n <= 10^9we only need powers:
2^0 through 2^30because:
2^30 = 1073741824and:
2^31 > 10^9Algorithm
Define a helper function that returns a digit signature.
One simple signature is the sorted digit string.
For example:
| Number | Signature |
|---|---|
128 | "128" |
821 | "128" |
46 | "46" |
64 | "46" |
Compute:
target = signature(n)Then for every power of two:
- Compute its signature.
- Compare with
target. - If equal, return
True.
If no match exists, return False.
Correctness
Two integers can be reordered into each other exactly when they contain the same digits with the same frequencies.
The signature function captures this property because sorting the digits produces the same result for all reorderings of the same multiset of digits.
Therefore, n can be reordered into a power of two if and only if some power of two has the same digit signature as n.
The algorithm checks every possible power of two in the valid range, so if such a power exists, the algorithm will find it and return True.
If no matching signature exists, then no digit reordering of n can form a power of two, so returning False is correct.
Complexity
There are only 31 relevant powers of two.
Let:
d = number of digits in n| Metric | Value | Why |
|---|---|---|
| Time | O(31 * d log d) | Sorting digits for each candidate |
| Space | O(d) | Temporary strings for signatures |
Since the number of powers is constant, the runtime is effectively constant.
Implementation
class Solution:
def reorderedPowerOf2(self, n: int) -> bool:
def signature(x: int) -> str:
return "".join(sorted(str(x)))
target = signature(n)
for power in range(31):
candidate = 1 << power
if signature(candidate) == target:
return True
return FalseCode Explanation
The helper function creates a digit signature:
def signature(x: int) -> str:
return "".join(sorted(str(x)))For example:
| Number | Signature |
|---|---|
128 | "128" |
821 | "128" |
Next:
target = signature(n)stores the signature of the input.
Then we generate powers of two:
for power in range(31):The expression:
1 << powercomputes:
2^powerFor each candidate power of two:
candidate = 1 << powerwe compare signatures:
if signature(candidate) == target:
return TrueIf no match is found after checking all powers:
return FalseTesting
def test_reordered_power_of_2():
s = Solution()
assert s.reorderedPowerOf2(1) is True
assert s.reorderedPowerOf2(10) is False
assert s.reorderedPowerOf2(16) is True
assert s.reorderedPowerOf2(24) is False
assert s.reorderedPowerOf2(46) is True
assert s.reorderedPowerOf2(218) is True
assert s.reorderedPowerOf2(125) is True
print("all tests passed")
test_reordered_power_of_2()Test meaning:
| Test | Why |
|---|---|
1 | Smallest power of two |
10 | Leading-zero reorderings are invalid |
16 | Already a power of two |
24 | Same digits cannot form a power of two |
46 | Reorders to 64 |
218 | Reorders to 128 |
125 | Reorders to 512 |