2048. Next Greater Numerically Balanced Number
Problem Description
A number is called numerically balanced when each digit that appears in the number occurs exactly as many times as the digit's value. For example, in the number 22
, the digit 2
appears exactly 2 times, making it balanced. Similarly, 333
is balanced because the digit 3
appears exactly 3 times.
Given an integer n
, you need to find the smallest numerically balanced number that is strictly greater than n
.
To clarify with examples:
22
is balanced: digit2
appears 2 times333
is balanced: digit3
appears 3 times4444
is balanced: digit4
appears 4 times122333
is balanced: digit1
appears 1 time, digit2
appears 2 times, digit3
appears 3 times123
is NOT balanced: digit1
appears 1 time (✓), but digit2
appears only 1 time instead of 2 (✗), and digit3
appears only 1 time instead of 3 (✗)
The task is to find the next such balanced number after the given input n
.
Flowchart Walkthrough
First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:
Is it a graph?
- No: The problem involves finding a numerically balanced number, not graph traversal with nodes and edges.
Need to solve for kth smallest/largest?
- No: We're looking for the next (smallest) balanced number after n, not the kth smallest/largest element.
Involves Linked Lists?
- No: The problem deals with integer manipulation and digit counting, not linked list operations.
Does the problem have small constraints?
- Yes: The constraint is n ∈ [0, 10^6], and we know that balanced numbers greater than 10^6 exist (like 1224444). This means we have a relatively small search space to explore.
Brute force / Backtracking?
- Yes: Given the small constraints and the need to check each number for the balanced property, we can use brute force enumeration. We systematically check each number starting from n+1 until we find one that satisfies the balanced condition.
Conclusion: The flowchart correctly leads us to a brute force/backtracking approach. While this problem uses more of a brute force enumeration rather than classical backtracking with recursive exploration and pruning, the solution fits this category because:
- We have small enough constraints to check all possibilities
- We systematically explore numbers in order (n+1, n+2, n+3...)
- For each candidate, we validate if it meets the balanced criteria
- We stop and return as soon as we find the first valid number
Intuition
The key insight is recognizing that numerically balanced numbers are relatively rare and follow specific patterns. For a digit d
to appear exactly d
times, we quickly realize that certain digits have natural limits. For instance, digit 9
would need to appear 9 times, requiring at least a 9-digit number. Similarly, digit 8
needs 8 occurrences, and so on.
This observation leads us to understand that smaller balanced numbers tend to use smaller digits. Numbers like 22
, 333
, 4444
are simple examples. More complex balanced numbers might combine multiple digits like 122333
(1 appears once, 2 appears twice, 3 appears three times).
Given the constraint that n ≤ 10^6
, we can deduce that the search space is bounded. Even if we start from a number close to 10^6
, we won't need to check too many numbers before finding a balanced one. The balanced number 1224444
(which is just above 10^6
) serves as an upper bound for our search.
Why brute force works here:
- Limited search space: We know we'll find an answer relatively quickly
- No pattern formula: There's no mathematical formula to directly compute the next balanced number
- Simple validation: Checking if a number is balanced is straightforward - count each digit's occurrences and verify they match the digit values
The approach becomes clear: start from n + 1
and check each subsequent number until we find one that's balanced. For each candidate number, we extract its digits, count their frequencies, and verify that each digit d
appears exactly d
times (or doesn't appear at all).
Learn more about Math and Backtracking patterns.
Solution Approach
Following the enumeration strategy mentioned in the reference approach, we implement a straightforward brute force solution that checks each number starting from n + 1
.
Algorithm Steps:
-
Start enumeration from
n + 1
: We usecount(n + 1)
to generate an infinite sequence starting from the next number aftern
. -
For each candidate number
x
, we need to verify if it's balanced:- Create a frequency array
cnt
of size 10 to track how many times each digit (0-9) appears - Extract digits from
x
using division and modulo operations
- Create a frequency array
-
Digit extraction process:
y = x # Make a copy to preserve x cnt = [0] * 10 # Initialize digit count array while y: y, v = divmod(y, 10) # Get quotient and remainder cnt[v] += 1 # Increment count for digit v
divmod(y, 10)
returns both the quotient (y // 10
) and remainder (y % 10
)- The remainder gives us the last digit
- We continue until all digits are extracted
-
Validation check:
all(v == 0 or i == v for i, v in enumerate(cnt))
- For each position
i
in the count array (representing digits 0-9) - The count
v
at that position must either be:0
: the digit doesn't appear in the number (valid)- Equal to
i
: the digiti
appears exactlyi
times (valid)
- If all digits satisfy this condition, the number is balanced
- For each position
-
Return the first valid number: As soon as we find a balanced number, we return it immediately since we're looking for the smallest one greater than
n
.
Why this works efficiently:
- The search space is bounded - we know balanced numbers exist not too far from any given
n
- The validation is O(log x) for a number
x
(number of digits) - We stop at the first valid result, ensuring we get the smallest balanced number greater than
n
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through finding the smallest balanced number greater than n = 20
.
Step 1: Start checking from n + 1 = 21
For x = 21
:
- Extract digits: 2 and 1
- Count array:
cnt = [0, 1, 1, 0, 0, 0, 0, 0, 0, 0]
- Digit 1 appears 1 time
- Digit 2 appears 1 time
- Validation:
- Position 0: count is 0 ✓ (digit 0 doesn't appear)
- Position 1: count is 1, and 1 == 1 ✓ (digit 1 appears once)
- Position 2: count is 1, but 2 ≠ 1 ✗ (digit 2 should appear twice)
- Result: NOT balanced
Step 2: Check x = 22
For x = 22
:
- Extract digits: 2 and 2
- Count array:
cnt = [0, 0, 2, 0, 0, 0, 0, 0, 0, 0]
- Digit 2 appears 2 times
- Validation:
- Position 0: count is 0 ✓
- Position 1: count is 0 ✓ (digit 1 doesn't appear)
- Position 2: count is 2, and 2 == 2 ✓ (digit 2 appears twice)
- Positions 3-9: all have count 0 ✓
- Result: BALANCED! Return 22
The algorithm correctly identifies 22
as the smallest balanced number greater than 20
.
Let's find the smallest balanced number greater than n = 49
.
Starting from 50, checking each number:
For numbers 50-121, none are balanced (you can verify each fails the validation check).
When we reach x = 122:
Digit extraction process:
122 % 10 = 2 → cnt[2]++ → cnt = [0,0,1,0,0,0,0,0,0,0] 12 % 10 = 2 → cnt[2]++ → cnt = [0,0,2,0,0,0,0,0,0,0] 1 % 10 = 1 → cnt[1]++ → cnt = [0,1,2,0,0,0,0,0,0,0]
Validation check:
- Digit 0: appears 0 times ✓
- Digit 1: appears 1 time, 1 == 1 ✓
- Digit 2: appears 2 times, 2 == 2 ✓
- Digits 3-9: all appear 0 times ✓
Since all conditions are satisfied, 122
is balanced and is our answer.
Solution Implementation
1from itertools import count
2
3class Solution:
4 def nextBeautifulNumber(self, n: int) -> int:
5 # Start checking from n + 1 onwards
6 for candidate in count(n + 1):
7 # Count the frequency of each digit in the current number
8 digit_count = [0] * 10 # Array to store count of digits 0-9
9 temp_num = candidate
10
11 # Extract each digit and count its occurrences
12 while temp_num > 0:
13 temp_num, digit = divmod(temp_num, 10)
14 digit_count[digit] += 1
15
16 # Check if the number is beautiful:
17 # For each digit (0-9), either it doesn't appear (count is 0)
18 # or it appears exactly as many times as its value
19 is_beautiful = all(
20 count == 0 or digit == count
21 for digit, count in enumerate(digit_count)
22 )
23
24 if is_beautiful:
25 return candidate
26
1class Solution {
2 public int nextBeautifulNumber(int n) {
3 // Start checking from n + 1 onwards
4 for (int candidate = n + 1; ; candidate++) {
5 // Array to count occurrences of each digit (0-9)
6 int[] digitCount = new int[10];
7
8 // Count the frequency of each digit in the current number
9 for (int temp = candidate; temp > 0; temp /= 10) {
10 digitCount[temp % 10]++;
11 }
12
13 // Check if the number is beautiful
14 boolean isBeautiful = true;
15
16 // A beautiful number has each digit d appearing exactly d times
17 for (int temp = candidate; temp > 0; temp /= 10) {
18 int digit = temp % 10;
19 // If digit value doesn't match its frequency, not beautiful
20 if (digit != digitCount[digit]) {
21 isBeautiful = false;
22 break;
23 }
24 }
25
26 // Return the first beautiful number found
27 if (isBeautiful) {
28 return candidate;
29 }
30 }
31 }
32}
33
1class Solution {
2public:
3 int nextBeautifulNumber(int n) {
4 // Iterate through numbers starting from n + 1 until we find a beautiful number
5 for (int candidate = n + 1;; ++candidate) {
6 // Count frequency of each digit (0-9) in the current number
7 int digitFrequency[10] = {0};
8
9 // Extract each digit and count its frequency
10 for (int temp = candidate; temp > 0; temp /= 10) {
11 int digit = temp % 10;
12 ++digitFrequency[digit];
13 }
14
15 // Check if the current number is beautiful
16 // A beautiful number has each digit appearing exactly as many times as its value
17 bool isBeautiful = true;
18
19 // Verify each digit appears exactly as many times as its value
20 for (int temp = candidate; temp > 0; temp /= 10) {
21 int digit = temp % 10;
22
23 // If digit doesn't appear exactly 'digit' times, it's not beautiful
24 if (digit != digitFrequency[digit]) {
25 isBeautiful = false;
26 break;
27 }
28 }
29
30 // Return the first beautiful number found
31 if (isBeautiful) {
32 return candidate;
33 }
34 }
35 }
36};
37
1/**
2 * Finds the next beautiful number greater than n.
3 * A beautiful number is one where each digit d appears exactly d times.
4 * For example: 122333 is beautiful (1 appears 1 time, 2 appears 2 times, 3 appears 3 times)
5 * @param n - The input number
6 * @returns The smallest beautiful number greater than n
7 */
8function nextBeautifulNumber(n: number): number {
9 // Start checking from n + 1 onwards
10 for (let candidate = n + 1; ; candidate++) {
11 // Initialize array to count occurrences of each digit (0-9)
12 const digitCounts: number[] = Array(10).fill(0);
13
14 // Count the frequency of each digit in the current candidate number
15 let tempNumber = candidate;
16 while (tempNumber > 0) {
17 const lastDigit = tempNumber % 10;
18 digitCounts[lastDigit]++;
19 tempNumber = Math.floor(tempNumber / 10);
20 }
21
22 // Check if current candidate is a beautiful number
23 let isBeautiful = true;
24 for (let digit = 0; digit < 10; digit++) {
25 // If a digit appears, it must appear exactly 'digit' times
26 // (e.g., digit 2 must appear exactly 2 times if it appears at all)
27 if (digitCounts[digit] > 0 && digitCounts[digit] !== digit) {
28 isBeautiful = false;
29 break;
30 }
31 }
32
33 // Return the first beautiful number found
34 if (isBeautiful) {
35 return candidate;
36 }
37 }
38}
39
Time and Space Complexity
The time complexity is O(M - n)
, where M = 1224444
represents the maximum beautiful number we need to check. The algorithm iterates through integers starting from n + 1
until it finds a beautiful number. In the worst case, when n
is close to the largest beautiful number, we need to check approximately M - n
numbers. For each number x
, we extract its digits (which takes O(log x)
time) and verify if it's beautiful (which takes O(10) = O(1)
time to check the count array). Since the maximum value we check is bounded by M = 1224444
, the digit extraction is O(log M) = O(7) = O(1)
. Therefore, the overall time complexity is O(M - n)
.
The space complexity is O(1)
. The algorithm uses a fixed-size array cnt
of length 10 to count digit occurrences, and a few integer variables (x
, y
, v
). The space usage doesn't depend on the input size n
, making it constant space.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Digit 0 Validation Error
A critical pitfall is incorrectly handling digit 0
. Since 0
cannot appear 0 times when it's present in the number, the validation logic v == 0 or i == v
breaks for digit 0
at position i=0
.
Problem Example:
- Number
1022
would incorrectly pass validation:- Digit
0
appears 1 time, buti=0
requires it to appear 0 times (impossible!) - This creates a logical contradiction
- Digit
Solution:
Add special handling for digit 0
:
is_beautiful = all(
(i == 0 and count == 0) or # Digit 0 must not appear
(i != 0 and (count == 0 or i == count)) # Other digits
for i, count in enumerate(digit_count)
)
2. Integer Overflow for Large Inputs
For very large values of n
, continuously incrementing might cause performance issues or theoretical overflow concerns in other languages (though Python handles big integers automatically).
Solution: Add an upper bound check or use mathematical properties of balanced numbers:
# Balanced numbers have predictable patterns and maximum lengths # The largest possible balanced number has at most 10 digits if candidate > 9876543210: # Theoretical maximum break # No valid answer exists
3. Leading Zero Confusion
When extracting digits, ensure you're not accidentally considering leading zeros (though this doesn't happen with integer representation).
Solution: The current approach naturally avoids this since we work with integers directly, but be careful if converting to strings:
# Avoid: str(candidate).count(str(digit)) # This could misinterpret numbers in string format
4. Inefficient Enumeration Range
Starting from n+1
and checking every single number can be inefficient for large gaps between balanced numbers.
Solution: Pre-compute or use mathematical patterns to skip impossible candidates:
# Skip numbers with digits > 9 in their digit count
# For example, if we see digit 5 appearing 6+ times, skip
if any(count > 9 for count in digit_count):
continue # This can never be balanced
The three-steps of Depth First Search are:
- Identify states;
- Draw the state-space tree;
- DFS on the state-space tree.
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Backtracking Template Prereq DFS with States problems dfs_with_states Combinatorial search problems Combinatorial search problems involve finding groupings and assignments of objects that satisfy certain conditions Finding all permutations combinations subsets and solving Sudoku are classic combinatorial problems The time complexity of combinatorial problems often grows rapidly with the size of
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
Want a Structured Path to Master System Design Too? Don’t Miss This!