2165. Smallest Value of the Rearranged Number


Problem Description

You are given an integer num. The task is to rearrange the digits of num in such a way that the resulting number is the smallest possible value and doesn't have any leading zeros. Importantly, you must maintain the sign of the original number; if the input number is negative, the result should also be negative, and the same for a positive number. The requirement is to return this minimum possible rearreganged number.

Intuition

To solve this problem, we can utilize a counting sort-like approach since we're dealing with individual digits which are only from 0 to 9. Here’s the intuition broken down into steps:

  1. Handling Zero: If the number is 0, return it directly since 0 cannot be rearranged to get a smaller number.

  2. Digit Counting: Count how many times each digit from 0 to 9 appears in the number using a list where the index corresponds to the digit and the value at that index represents the count.

  3. Handle Negative Numbers: If the number is negative, to get the smallest possible number after rearrangement, we should start the number with the largest digit available and proceed to the smallest. Since leading zeros are not allowed, we only arrange the nonzero digits.

  4. Handle Positive Numbers: a. If there are any zeros (as recorded in the digit counting step), make sure to place a nonzero digit at the beginning to avoid leading zeros. This is achieved by looking for the first nonzero count from 1 to 9, adding it to the answer string, and decreasing its count. b. After placing the first nonzero digit, append the remaining digits starting from 0 to 9 to ensure a minimal value.

  5. Returning the Result: Combine the arranged digits into a single integer, preserving the sign, and return this integer as the answer.

This approach effectively sorts the digits to form the smallest (or largest if negative) possible number without using any extra sorting function, and the counting steps ensure that no leading zeros will appear in the final arrangement.

Learn more about Math and Sorting patterns.

Not Sure What to Study? Take the 2-min Quiz to Find Your Missing Piece:

Depth first search is equivalent to which of the tree traversal order?

Solution Approach

The solution follows a direct approach, implementing the intuition we described earlier. Here's how the code breaks down the problem and applies an algorithm to solve it:

  1. Initialization and Handling of Zero:

    • If num is 0, we return 0 immediately as we cannot rearrange it for a smaller value.
    • Initialize a counter array cnt with 10 zeroes, which will serve to count the occurrences of each digit (0-9).
    • Record the sign of num in a boolean neg and use abs(num) to work with the absolute value, simplifying our logic for rearrangement.
  2. Counting Digits:

    • A while loop is used to extract each digit from num using divmod(num, 10), which provides quotient and remainder - the latter being the digit we're counting.
    • Increment the count of the extracted digit in the cnt array.
  3. Constructing the Smallest/Largest Number Based on Sign:

    • Initialize an empty string ans to build the final digit string.
    • If the number is negative (neg is True), iterate from 9 down to 0:
      • For each digit i, if the count cnt[i] is non-zero, append the digit i converted to a string, multiplied by its count, to ans. This assembles the largest possible number from the digits.
    • If the number is positive (neg is False):
      • First, find and place a non-zero digit if there are any zeros to avoid leading zeros. Iterate from 1 to 9 and on finding a non-zero count, append that digit to ans and decrement its count.
      • Next, append the rest of the digits in ascending order to build the smallest possible number. Iterate from 0 to 9 and for each digit i, if the count cnt[i] is non-zero, append the digit multiplied by its count to ans.
  4. Finalizing the Answer:

    • Since ans is a string, it is converted back to an integer. The sign is reintroduced by negating the result if the original number was negative.

In summary, the code uses the counting sort technique to tally the occurrences of each digit and then rearranges the digits according to whether the number is positive or negative, to return the smallest possible value without leading zeros. It leverages simple array manipulation and string concatenation to avoid more complex sorting algorithms or additional data structures.

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

Depth first search is equivalent to which of the tree traversal order?

Example Walkthrough

Consider the integer num = 310. We need to find the smallest possible value by rearranging num's digits without leading zeros.

  1. Handling Zero:

    • num is not 0, so we proceed with the solution.
  2. Digit Counting:

    • We count the occurrences of each digit:
      • 3 appears once.
      • 1 appears once.
      • 0 appears once.
    • The counter array cnt is thus [1, 1, 0, 1, 0, 0, 0, 0, 0, 0].
  3. Handle Positive Numbers:

    • Since num is positive, we follow the steps for positive numbers. a) We pick the smallest nonzero digit to avoid a leading zero. This is the digit 1.
    • We place 1 at the beginning, and the cnt array updates to [1, 0, 0, 1, 0, 0, 0, 0, 0, 0]. b) Now we append the rest of the digits sorted in ascending order. The next smallest digit is 0, followed by 3.
    • We append these to get the number 103.
  4. Returning the Result:

    • Now, we combine the digits to form the integer 103, which is the smallest variation of 310 with no leading zero.

On the other hand, consider the integer num = -310. For negative numbers, the smallest value is achieved by arranging digits in reverse order, from largest to smallest.

  1. Handling Zero:

    • num is not 0, so we proceed with the solution.
  2. Digit Counting:

    • The occurrences of each digit are the same as above, and the counter array cnt doesn't change.
  3. Handle Negative Numbers:

    • Since num is negative, the largest digit, which is 3, goes first, followed by 1, then 0.
    • We get the negative number -310 since rearranging the digits in descending order gives the same number. We don't need to change anything for this specific example, as it is already in the required form.

Thus, by following the counting sort-like approach, we can efficiently determine the smallest possible rearrangement of num while preserving the original sign and avoiding any leading zeros.

Solution Implementation

1class Solution:
2    def smallest_number(self, num: int) -> int:
3        # If the number is zero, just return it
4        if num == 0:
5            return 0
6
7        # Initialize a list to store the count of each digit
8        digit_count = [0] * 10
9
10        # Determine if the number is negative
11        is_negative = num < 0
12
13        # Work with the absolute value of the number
14        num = abs(num)
15
16        # Count the occurrences of each digit in the number
17        while num:
18            num, remainder = divmod(num, 10)
19            digit_count[remainder] += 1
20
21        # Create an empty string to build the answer
22        answer_str = ""
23
24        # If the number is negative, we create the largest number with its digits
25        if is_negative:
26            for i in range(9, -1, -1):  # Start from 9 to 0
27                if digit_count[i]:
28                    answer_str += str(i) * digit_count[i]
29            # Convert the string to a negative integer
30            return -int(answer_str)
31
32        # If the number is positive and contains zeros,
33        # place the smallest non-zero digit at the start
34        if digit_count[0]:
35            for i in range(1, 10):
36                if digit_count[i]:
37                    answer_str += str(i)
38                    digit_count[i] -= 1
39                    break
40
41        # Append the remaining digits in ascending order
42        for i in range(10):
43            if digit_count[i]:
44                answer_str += str(i) * digit_count[i]
45
46        # Convert the string to an integer
47        return int(answer_str)
48
1class Solution {
2
3    // This method finds the smallest number that can be formed by rearranging the digits of the given number.
4    public long smallestNumber(long num) {
5        // If the number is 0, return it as the smallest number without any processing.
6        if (num == 0) {
7            return 0;
8        }
9
10        // An array to count the occurrences of each digit in the number.
11        int[] digitCounts = new int[10];
12
13        // Flag to check if the original number is negative.
14        boolean isNegative = num < 0;
15
16        // Take the absolute value in case the number is negative for ease of processing.
17        num = Math.abs(num);
18
19        // Count the occurrences of each digit in the number.
20        while (num != 0) {
21            digitCounts[(int) (num % 10)]++;
22            num /= 10;
23        }
24
25        // This will hold the smallest number that we form by rearranging the digits.
26        long result = 0;
27
28        // If the original number is negative, we want the largest absolute value,
29        // which when negated, gives the smallest possible negative number.
30        if (isNegative) {
31            // Construct the number from digits in descending order.
32            for (int i = 9; i >= 0; --i) {
33                while (digitCounts[i]-- > 0) {
34                    result = result * 10 + i;
35                }
36            }
37            // Return the negated result since the original number was negative.
38            return -result;
39        }
40      
41        // If number is positive and contains zeros, we must place the smallest non-zero digit at the
42        // front to get the smallest possible number, then follow with any zeros.
43        if (digitCounts[0] > 0) {
44            for (int i = 1; i < 10; ++i) {
45                if (digitCounts[i] > 0) {
46                    result = result * 10 + i; // Place the smallest non-zero digit first.
47                    digitCounts[i]--;
48                    break; // Break after placing the first non-zero digit.
49                }
50            }
51        }
52
53        // After placing the smallest non-zero digit, place the remaining digits in ascending order.
54        for (int i = 0; i < 10; ++i) {
55            while (digitCounts[i]-- > 0) {
56                result = result * 10 + i;
57            }
58        }
59
60        // Return the final smallest number.
61        return result;
62    }
63}
64
1#include <vector>
2#include <cmath>
3
4class Solution {
5public:
6    // Function to find the smallest permutation of the given number
7    long long smallestNumber(long long num) {
8        // Return 0 if the number is already 0
9        if (num == 0) return 0;
10
11        // Vector to count the occurrences of each digit
12        std::vector<int> digitCount(10, 0);
13
14        // Check if the number is negative
15        bool isNegative = num < 0;
16
17        // Work with the absolute value of num
18        num = std::abs(num);
19
20        // Count occurrences of each digit
21        while (num) {
22            digitCount[num % 10]++;
23            num /= 10;
24        }
25
26        long long smallestNum = 0;
27
28        // If the number is negative, build the largest number possible and then add the sign
29        if (isNegative) {
30            for (int i = 9; i >= 0; --i) {
31                while (digitCount[i]--) {
32                    smallestNum = smallestNum * 10 + i;
33                }
34            }
35            return -smallestNum; // Return the negative value
36        }
37
38        // If the number has zeroes, we must handle them properly to avoid leading zeroes
39        if (digitCount[0]) {
40            // Find the smallest non-zero digit to place at the beginning
41            for (int i = 1; i < 10; ++i) {
42                if (digitCount[i]) {
43                    smallestNum = smallestNum * 10 + i;
44                    digitCount[i]--;
45                    break;
46                }
47            }
48        }
49
50        // Build the smallest number by adding digits in ascending order
51        for (int i = 0; i < 10; ++i) {
52            while (digitCount[i]--) {
53                smallestNum = smallestNum * 10 + i;
54            }
55        }
56
57        return smallestNum;
58    }
59};
60
1// Import necessary functionalities from 'math' module
2import { abs } from "math";
3
4// Function to find the smallest permutation of the given number
5function smallestNumber(num: number): number {
6    // Return 0 if the number is already 0
7    if (num === 0) return 0;
8
9    // Array to count the occurrences of each digit
10    let digitCount: number[] = Array(10).fill(0);
11
12    // Check if the number is negative
13    let isNegative: boolean = num < 0;
14
15    // Work with the absolute value of num
16    num = abs(num);
17
18    // Count occurrences of each digit
19    while (num > 0) {
20        digitCount[num % 10]++;
21        num = Math.floor(num / 10);
22    }
23
24    // Variable to hold the smallest (or largest if negative) permutation of the number
25    let smallestNum: number = 0;
26
27    // If the number is negative, build the largest number possible and then add the sign
28    if (isNegative) {
29        for (let i = 9; i >= 0; --i) {
30            while (digitCount[i] > 0) {
31                smallestNum = smallestNum * 10 + i;
32                digitCount[i]--;
33            }
34        }
35        // Return the negative value, as the original number was negative
36        return -smallestNum;
37    }
38
39    // If the number has zeroes, we must handle them properly to avoid leading zeroes
40    if (digitCount[0] > 0) {
41        // Find the smallest non-zero digit to place at the beginning
42        for (let i = 1; i < 10; ++i) {
43            if (digitCount[i] > 0) {
44                smallestNum = smallestNum * 10 + i;
45                digitCount[i]--;
46                break;
47            }
48        }
49    }
50
51    // Build the smallest number by adding digits in ascending order
52    for (let i = 0; i < 10; ++i) {
53        while (digitCount[i] > 0) {
54            smallestNum = smallestNum * 10 + i;
55            digitCount[i]--;
56        }
57    }
58
59    // Return the smallest permutation of the original number
60    return smallestNum;
61}
62
Not Sure What to Study? Take the 2-min Quiz:

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

Time and Space Complexity

The time complexity of the provided solution is O(n + 10) which simplifies to O(n) where n represents the number of digits in the integer num. This is because we first iterate through all digits of the input num to count them (which contributes to O(n)), and then we iterate through the count array of 10 digits (which contributes to O(10) but constants are omitted in Big O notation).

The space complexity of the solution is O(10), which simplifies to O(1) - constant space complexity. This is because the count array cnt has a fixed size of 10, regardless of the size of num. The string ans also doesn't count towards space complexity in this analysis as it simply corresponds to the size of the output, which is not considered additional space used by the algorithm.

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

Fast Track Your Learning with Our Quick Skills Quiz:

Given a sorted array of integers and an integer called target, find the element that equals to the target and return its index. Select the correct code that fills the ___ in the given code snippet.

1def binary_search(arr, target):
2    left, right = 0, len(arr) - 1
3    while left ___ right:
4        mid = (left + right) // 2
5        if arr[mid] == target:
6            return mid
7        if arr[mid] < target:
8            ___ = mid + 1
9        else:
10            ___ = mid - 1
11    return -1
12
1public static int binarySearch(int[] arr, int target) {
2    int left = 0;
3    int right = arr.length - 1;
4
5    while (left ___ right) {
6        int mid = left + (right - left) / 2;
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16
1function binarySearch(arr, target) {
2    let left = 0;
3    let right = arr.length - 1;
4
5    while (left ___ right) {
6        let mid = left + Math.trunc((right - left) / 2);
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16

Recommended Readings


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫