Number of Balanced Integers in a Range solution and explanation
4 more videos on this problem
Leetcode 3791 | Number of Balanced Integers in a Range | Complete Explanation | Beginner FriendlyCodeWithMeGuys · 23:56 · 583 views
3791. Number of Balanced Integers in a Range (Leetcode Hard)Programming Live with Larry · 23:56 · 140 views
LeetCode 3791. Number of Balanced Integers in a Range | Weekly Contest 482 | Digit DPyoBro · 0:34 · 42 views
3791. Number of Balanced Integers In a Range (LeetCode Hard)WYCode · 42:49 · 21 views
3791. Number of Balanced Integers in a RangeHui Xu · 16:31 · 7 views
The problem
You are given two integers low and high.
An integer is called balanced if it satisfies both of the following conditions:
- It contains at least two digits.
- The sum of digits at even positions is equal to the sum of digits at odd positions (the leftmost digit has position 1).
Return an integer representing the number of balanced integers in the range [low, high] (both inclusive).
Example 1:
Input: low = 1, high = 100
Output: 9
Explanation:
The 9 balanced numbers between 1 and 100 are 11, 22, 33, 44, 55, 66, 77, 88, and 99.
Example 2:
Input: low = 120, high = 129
Output: 1
Explanation:
Only 121 is balanced because the sum of digits at even and odd positions are both 2.
Example 3:
Input: low = 1234, high = 1234
Output: 0
Explanation:
1234 is not balanced because the sum of digits at odd positions (1 + 3 = 4) does not equal the sum at even positions (2 + 4 = 6).
Constraints:
1 <= low <= high <= 1015
Approach overview
Problem Overview: Given two integers low and high, count how many numbers in this range are balanced. A balanced integer typically has an even number of digits where the sum of the first half equals the sum of the second half. Brute forcing the range quickly becomes infeasible when the bounds grow large.
Approach 1: Brute Force Enumeration (O(N * d) time, O(1) space)
The most direct method iterates through every number from low to high. Convert each number to digits, check whether the digit count is even, then compute the sum of the first half and the second half. If the sums match, increment the result. Each check costs O(d) where d is the number of digits, so the total runtime becomes O(N * d) where N = high - low. This approach is simple and useful for validating logic on small ranges, but it fails for large constraints because the range can reach billions.
Approach 2: Digit Dynamic Programming (Digit DP) (O(d * sum * states) time, O(d * sum * states) space)
The efficient solution uses Digit DP, a technique built on dynamic programming for counting numbers with digit constraints. Instead of iterating through every integer, construct numbers digit by digit while tracking the difference between the first-half digit sum and the second-half digit sum. The DP state typically includes the current digit index, whether the current prefix is tight with the upper bound, the current sum difference, and whether the number has started.
When the position is in the first half of the digits, add the digit value to the running sum difference. When in the second half, subtract it. A number is valid if the final difference equals zero and the length is even. Compute the count of valid numbers up to high and subtract the count up to low - 1. This transforms a huge search space into a manageable state space bounded by digit count and possible sums.
Digit DP avoids enumerating each number individually. Instead, it reuses previously computed states through memoization, dramatically reducing work. This technique frequently appears in advanced counting problems involving ranges and digit constraints.
Recommended for interviews: Start by explaining the brute force idea to show you understand the definition of a balanced number. Then transition to Digit DP, which is the expected optimal solution. Interviewers look for recognition that iterating over the entire range is too slow and that digit-by-digit counting with memoized states solves the problem efficiently.
Solution
First, if high < 11, there are no balanced integers in the range, so we directly return 0. Otherwise, we update low to max(low, 11).
Then we design a function dfs(pos, diff, lim), which represents processing the pos-th digit of the number, where diff is the difference between the sum of digits at odd positions and the sum of digits at even positions, and lim indicates whether the current digit is constrained by the upper bound. The function returns the number of balanced integers that can be constructed from the current state.
The execution logic of the function is as follows:
- If
posexceeds the length of the number, it means all digits have been processed. Ifdiff = 0, the current number is a balanced integer, return1; otherwise, return0. - Calculate the upper bound
upfor the current digit. If constrained, it equals the current digit of the number; otherwise, it is9. - Iterate through all possible digits
ifor the current position. For each digiti, recursively calldfs(pos + 1, diff + i times (1 if pos \% 2 == 0 else -1), lim \&\& i == up), and accumulate the results. - Return the accumulated result.
We first calculate the number of balanced integers a in the range [1, low - 1], then calculate the number of balanced integers b in the range [1, high], and finally return b - a.
To avoid redundant calculations, we use memoization to store previously computed states.
The time complexity is O(log^2 M times D^2), and the space complexity is O(log^2 M times D). Here, M is the value of high, and D = 10.
class Solution:
def countBalanced(self, low: int, high: int) -> int:
@cache
def dfs(pos: int, diff: int, lim: int) -> int:
if pos >= len(num):
return 1 if diff == 0 else 0
res = 0
up = int(num[pos]) if lim else 9
for i in range(up + 1):
res += dfs(
pos + 1, diff + i * (1 if pos % 2 == 0 else -1), lim and i == up
)
return res
if high < 11:
return 0
low = max(low, 11)
num = str(low - 1)
a = dfs(0, 0, True)
dfs.cache_clear()
num = str(high)
b = dfs(0, 0, True)
return b - aclass Solution {
private char[] num;
private Long[][] f;
private final int base = 90;
public long countBalanced(long low, long high) {
if (high < 11) {
return 0;
}
low = Math.max(low, 11);
num = String.valueOf(low - 1).toCharArray();
f = new Long[num.length][base << 1 | 1];
long a = dfs(0, 0, true);
num = String.valueOf(high).toCharArray();
f = new Long[num.length][base << 1 | 1];
long b = dfs(0, 0, true);
return b - a;
}
private long dfs(int pos, int diff, boolean lim) {
if (pos >= num.length) {
return diff == 0 ? 1 : 0;
}
if (!lim && f[pos][diff + base] != null) {
return f[pos][diff + base];
}
int up = lim ? num[pos] - '0' : 9;
long res = 0;
for (int i = 0; i <= up; ++i) {
res += dfs(pos + 1, diff + i * (pos % 2 == 0 ? 1 : -1), lim && i == up);
}
if (!lim) {
f[pos][diff + base] = res;
}
return res;
}
}class Solution {
public:
string num;
long long f[20][181];
static constexpr int base = 90;
long long dfs(int pos, int diff, bool lim) {
if (pos >= (int) num.size()) {
return diff == 0 ? 1LL : 0LL;
}
if (!lim && f[pos][diff + base] != -1) {
return f[pos][diff + base];
}
int up = lim ? num[pos] - '0' : 9;
long long res = 0;
for (int i = 0; i <= up; ++i) {
res += dfs(pos + 1, diff + i * (pos % 2 == 0 ? 1 : -1), lim && i == up);
}
if (!lim) {
f[pos][diff + base] = res;
}
return res;
}
long long countBalanced(long long low, long long high) {
if (high < 11) {
return 0;
}
low = max(low, 11LL);
num = to_string(low - 1);
memset(f, -1, sizeof(f));
long long a = dfs(0, 0, true);
num = to_string(high);
memset(f, -1, sizeof(f));
long long b = dfs(0, 0, true);
return b - a;
}
};function countBalanced(low: number, high: number): number {
if (high < 11) {
return 0;
}
if (low < 11) {
low = 11;
}
const base = 90;
let num: string;
let f: number[][];
function dfs(pos: number, diff: number, lim: boolean): number {
if (pos >= num.length) {
return diff === 0 ? 1 : 0;
}
if (!lim && f[pos][diff + base] !== -1) {
return f[pos][diff + base];
}
const up = lim ? num.charCodeAt(pos) - 48 : 9;
let res = 0;
for (let i = 0; i <= up; ++i) {
res += dfs(pos + 1, diff + i * (pos % 2 === 0 ? 1 : -1), lim && i === up);
}
if (!lim) {
f[pos][diff + base] = res;
}
return res;
}
num = String(low - 1);
f = Array.from({ length: num.length }, () => Array((base << 1) | 1).fill(-1));
const a = dfs(0, 0, true);
num = String(high);
f = Array.from({ length: num.length }, () => Array((base << 1) | 1).fill(-1));
const b = dfs(0, 0, true);
return b - a;
}func countBalanced(low int64, high int64) int64 {
if high < 11 {
return 0
}
if low < 11 {
low = 11
}
const base = 90
var num []byte
var f [20][181]int64
var dfs func(pos int, diff int, lim bool) int64
dfs = func(pos int, diff int, lim bool) int64 {
if pos >= len(num) {
if diff == 0 {
return 1
}
return 0
}
if !lim && f[pos][diff+base] != -1 {
return f[pos][diff+base]
}
up := 9
if lim {
up = int(num[pos] - '0')
}
var res int64 = 0
for i := 0; i <= up; i++ {
if pos%2 == 0 {
res += dfs(pos+1, diff+i, lim && i == up)
} else {
res += dfs(pos+1, diff-i, lim && i == up)
}
}
if !lim {
f[pos][diff+base] = res
}
return res
}
num = []byte(fmt.Sprint(low - 1))
for i := range f {
for j := range f[i] {
f[i][j] = -1
}
}
a := dfs(0, 0, true)
num = []byte(fmt.Sprint(high))
for i := range f {
for j := range f[i] {
f[i][j] = -1
}
}
b := dfs(0, 0, true)
return b - a
}Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Brute Force Enumeration | O(N * d) | O(1) | Small ranges or quick correctness checks |
| Digit Dynamic Programming (Digit DP) | O(d * sum * states) | O(d * sum * states) | Large ranges where direct enumeration is infeasible |
Frequently asked questions
Is Number of Balanced Integers in a Range easy or hard?
Number of Balanced Integers in a Range is categorized as a Hard problem. The difficulty comes from designing correct Digit DP states and handling constraints like digit position, prefix tightness, and balanced sum tracking.
Number of Balanced Integers in a Range Python/Java solution
Implement a Digit DP function that counts valid numbers up to a bound. The function processes digits from left to right, tracks the sum difference between halves, and respects the tight bound condition. The same logic translates cleanly to Python, Java, C++, Go, and TypeScript.
How to solve Number of Balanced Integers in a Range in O(d * states)?
Use Digit DP to count valid numbers up to a limit. Track the current digit position, tight constraint with the bound, and the difference between the first-half and second-half digit sums. Evaluate counts for high and subtract counts for low - 1 to get the final answer.
What is the best approach for Number of Balanced Integers in a Range?
Digit Dynamic Programming (Digit DP) is the most efficient approach. Instead of iterating through every number in the range, the algorithm builds numbers digit by digit while tracking the difference between the first-half and second-half digit sums. Memoization avoids recomputation of identical states, reducing the search space dramatically.
Is Number of Balanced Integers in a Range asked at Google/Amazon/Meta?
Digit DP counting problems similar to this frequently appear in interviews at companies like Google, Amazon, and Meta. Interviewers use them to test dynamic programming skills, state design, and the ability to optimize brute-force enumeration.
What data structure is used in Number of Balanced Integers in a Range?
The solution relies on dynamic programming with memoization, typically implemented using arrays or hash maps for DP states. Recursion or iterative DP is used to traverse digits while caching computed states.
What is the time complexity of Number of Balanced Integers in a Range?
The optimal Digit DP solution runs in roughly O(d * sum * states) time where d is the number of digits in the bound and sum represents possible digit sums. The brute force method takes O(N * d) time where N is the size of the range, which becomes impractical for large inputs.
