LeetCode 2165 - Smallest Value of the Rearranged Number
In this problem, we are given an integer num, which may be positive, negative, or zero. Our goal is to rearrange its digits so that the resulting number is as small as possible while preserving the original sign. The important detail is that the sign cannot change.
Difficulty: 🟡 Medium
Topics: Math, Sorting
Solution
Problem Understanding
In this problem, we are given an integer num, which may be positive, negative, or zero. Our goal is to rearrange its digits so that the resulting number is as small as possible while preserving the original sign.
The important detail is that the sign cannot change. If the number is positive, the rearranged number must also remain positive. If the number is negative, the rearranged number must stay negative.
The problem also states that the resulting number cannot contain leading zeros. This means that for positive numbers, we cannot place 0 at the beginning of the rearranged number. For example, rearranging 310 into 013 is invalid because integers do not allow leading zeros in their representation.
For negative numbers, the interpretation is slightly different. Since a more negative number is numerically smaller, we actually want to maximize the absolute value. For example:
-7650 < -6705- Therefore
-7650is considered smaller
This means:
- Positive numbers should have their digits arranged in ascending order
- Negative numbers should have their digits arranged in descending order
The constraints are relatively small:
-10^15 <= num <= 10^15
A number with magnitude 10^15 has at most 16 digits including the sign, so the input size is tiny. This means sorting digits is completely feasible.
Some important edge cases include:
- Numbers containing many zeros, such as
100200 - Numbers that are already minimal
- Negative numbers
- The value
0 - Numbers with repeated digits
- Positive numbers where the smallest digit is
0
A naive implementation can easily fail when handling leading zeros correctly.
Approaches
Brute Force Approach
A brute force solution would generate every possible permutation of the digits, convert each permutation into a valid number, filter out arrangements with leading zeros, and then select the minimum valid value.
For example, for 310, we would generate:
013031103130301310
Then we discard invalid leading-zero numbers and choose the smallest remaining value.
This approach is correct because it explicitly checks every possible arrangement. However, it is computationally impractical because the number of permutations grows factorially.
If the number has n digits, there are n! permutations. Even with only 15 digits, this becomes astronomically large.
Optimal Approach
The key observation is that we do not need to try every permutation. We only need to construct the lexicographically smallest valid arrangement.
For positive numbers:
- Sort digits in ascending order
- Move the first non-zero digit to the front
- Place all zeros immediately after it
- Append the remaining digits
This guarantees the smallest possible positive number without leading zeros.
For negative numbers:
- Sort digits in descending order
- Build the largest possible absolute value
- Reapply the negative sign
This works because among negative numbers, a larger magnitude corresponds to a smaller value.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n! × n) | O(n!) | Generates all digit permutations |
| Optimal | O(n log n) | O(n) | Uses sorting and greedy digit placement |
Algorithm Walkthrough
Positive Number Case
- Convert the number into a list of digit characters.
This makes it easy to sort and rearrange individual digits. 2. Sort the digits in ascending order.
Smaller digits should appear earlier because we want the smallest possible value. 3. Handle leading zeros carefully.
After sorting, zeros may appear at the front. A leading zero is invalid, so we locate the first non-zero digit and move it to the beginning. 4. Keep all remaining digits in ascending order.
Once the first digit is fixed as the smallest non-zero digit, the rest should remain sorted to minimize the overall number. 5. Convert the rearranged digit list back into an integer.
Negative Number Case
- Remove the negative sign by taking the absolute value.
- Convert digits into a list.
- Sort digits in descending order.
For negative numbers, a larger absolute value produces a smaller final number. 4. Join the digits into a number. 5. Reapply the negative sign.
Special Case: Zero
If the input is 0, the result is simply 0.
Why it works
For positive numbers, placing the smallest non-zero digit first guarantees the smallest valid leading digit. Keeping the remaining digits in ascending order minimizes every subsequent position.
For negative numbers, maximizing the absolute value produces the numerically smallest negative number because larger magnitudes are more negative.
These greedy choices are always optimal because digit positions contribute independently according to place value.
Python Solution
class Solution:
def smallestNumber(self, num: int) -> int:
if num == 0:
return 0
# Negative number case
if num < 0:
digits = list(str(-num))
digits.sort(reverse=True)
return -int("".join(digits))
# Positive number case
digits = list(str(num))
digits.sort()
# Find first non-zero digit
first_non_zero = 0
while digits[first_non_zero] == '0':
first_non_zero += 1
# Place smallest non-zero digit first
digits[0], digits[first_non_zero] = (
digits[first_non_zero],
digits[0],
)
return int("".join(digits))
The implementation starts by handling the simplest special case, 0.
For negative numbers, the code converts the absolute value into digits, sorts them in descending order, joins them back together, and reapplies the negative sign.
For positive numbers, the digits are sorted in ascending order. Since zeros may appear at the front, the algorithm scans for the first non-zero digit and swaps it into the leading position. This preserves the smallest possible arrangement while avoiding leading zeros.
Finally, the digits are joined and converted back into an integer.
Go Solution
package main
import (
"sort"
"strconv"
)
func smallestNumber(num int64) int64 {
if num == 0 {
return 0
}
// Negative number case
if num < 0 {
digits := []byte(strconv.FormatInt(-num, 10))
sort.Slice(digits, func(i, j int) bool {
return digits[i] > digits[j]
})
value, _ := strconv.ParseInt(string(digits), 10, 64)
return -value
}
// Positive number case
digits := []byte(strconv.FormatInt(num, 10))
sort.Slice(digits, func(i, j int) bool {
return digits[i] < digits[j]
})
// Find first non-zero digit
firstNonZero := 0
for digits[firstNonZero] == '0' {
firstNonZero++
}
// Swap into front position
digits[0], digits[firstNonZero] =
digits[firstNonZero], digits[0]
value, _ := strconv.ParseInt(string(digits), 10, 64)
return value
}
The Go solution follows the same logic as the Python implementation.
One important difference is that Go uses []byte to manipulate characters efficiently. Sorting is implemented using sort.Slice, which allows custom comparison functions.
The final number is reconstructed using strconv.ParseInt.
Because the constraint is limited to 10^15, all results safely fit inside int64.
Worked Examples
Example 1
Input:
num = 310
Step 1: Convert to digits
| Operation | Result |
|---|---|
| Digits | ['3', '1', '0'] |
Step 2: Sort ascending
| Operation | Result |
|---|---|
| Sorted digits | ['0', '1', '3'] |
Step 3: Find first non-zero digit
| Index | Digit |
|---|---|
| 0 | 0 |
| 1 | 1 |
First non-zero digit is at index 1.
Step 4: Swap into front
| Before Swap | After Swap |
|---|---|
['0', '1', '3'] |
['1', '0', '3'] |
Step 5: Build number
103
Output:
103
Example 2
Input:
num = -7605
Step 1: Remove sign
7605
Step 2: Convert to digits
| Operation | Result |
|---|---|
| Digits | ['7', '6', '0', '5'] |
Step 3: Sort descending
| Operation | Result |
|---|---|
| Sorted digits | ['7', '6', '5', '0'] |
Step 4: Build number
7650
Step 5: Reapply negative sign
-7650
Output:
-7650
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n log n) | Sorting the digits dominates the runtime |
| Space | O(n) | Stores the digit array |
The number of digits is at most 16, so the algorithm is extremely efficient in practice. The sorting step dominates the runtime complexity.
Test Cases
solution = Solution()
assert solution.smallestNumber(310) == 103 # example case
assert solution.smallestNumber(-7605) == -7650 # negative example
assert solution.smallestNumber(0) == 0 # zero input
assert solution.smallestNumber(100) == 100 # leading zero handling
assert solution.smallestNumber(9070) == 7009 # multiple zeros
assert solution.smallestNumber(-1002) == -2100 # negative with zeros
assert solution.smallestNumber(12345) == 12345 # already minimal
assert solution.smallestNumber(54321) == 12345 # reverse sorted positive
assert solution.smallestNumber(-54321) == -54321 # already optimal negative
assert solution.smallestNumber(1000000) == 1000000 # many zeros
assert solution.smallestNumber(11111) == 11111 # repeated digits
assert solution.smallestNumber(-11111) == -11111 # repeated negative digits
assert solution.smallestNumber(9000000001) == 1000000009 # large zeros case
| Test | Why |
|---|---|
310 |
Basic positive example |
-7605 |
Basic negative example |
0 |
Special zero case |
100 |
Ensures no leading zeros |
9070 |
Multiple zeros in positive number |
-1002 |
Negative number with zeros |
12345 |
Already minimal arrangement |
54321 |
Requires full reordering |
-54321 |
Negative already optimal |
1000000 |
Many trailing zeros |
11111 |
Repeated digits |
-11111 |
Repeated negative digits |
9000000001 |
Large input with many zeros |
Edge Cases
Positive Numbers With Leading Zeros After Sorting
A very common bug occurs when sorting digits of a positive number containing zeros. For example, sorting 310 directly produces 013, which is invalid because integers cannot contain leading zeros.
The implementation fixes this by locating the first non-zero digit and swapping it into the front position.
Negative Numbers
Negative numbers reverse the optimization logic. For positive numbers we minimize the absolute value, but for negative numbers we maximize it.
For example:
-7650 < -5067
A naive solution that always sorts ascending would fail here. The implementation correctly sorts digits in descending order for negative inputs.
Input Equal to Zero
The number 0 is a special case because it has only one digit and no rearrangement is necessary.
Without explicitly handling this case, some implementations may attempt unnecessary digit processing. The solution immediately returns 0.
Numbers With Repeated Digits
Repeated digits can sometimes expose bugs in swapping logic or sorting assumptions.
For example:
11111
All permutations are identical, so the output should remain unchanged.
The implementation naturally handles this because sorting repeated digits does not alter their arrangement incorrectly.