1. Problem Statement
Given an integer n, we need to count the number of binary strings of length 2 * n such that:
The string contains exactly
nones (1).The string contains exactly
nzeros (0).In every prefix of the string, the number of
1s is greater than or equal to the number of0s.Return the answer modulo
10^9 + 7.
For example, when n = 2, the valid strings are:
1100
1010Therefore, the answer is 2.
2. Important Observation
The condition:
Every prefix must contain at least as many
1s as0s.
means that we can think of:
1as an opening operation.0as a closing operation.
We are never allowed to use more 0s than 1s at any point.
For example:
1010Prefix balances:
1 → ones = 1, zeros = 0
10 → ones = 1, zeros = 1
101 → ones = 2, zeros = 1
1010 → ones = 2, zeros = 2The balance never becomes negative.
But:
0110is invalid because its first prefix is:
0Here:
ones = 0
zeros = 1So the condition is violated.
3. Dynamic Programming Approach
We define:
dp[j]as the number of valid ways to construct the current string using j zeros.
We process the number of 1s one by one.
Suppose we have used:
i ones
j zerosThere are two possibilities for the last character.
Case 1: Add 1
Before adding 1, we had:
i - 1 ones
j zerosSo the number of ways is:
dp[i - 1][j]Case 2: Add 0
Before adding 0, we had:
i ones
j - 1 zerosSo the number of ways is:
dp[i][j - 1]Therefore:
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]However, we can only have:
j <= ibecause the number of zeros can never exceed the number of ones in any prefix.
4. Java Code
class Solution {
public int prefixStrings(int n) {
final int MOD = 1000000007;
long[] dp = new long[n + 1];
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp[j] = (dp[j] + dp[j - 1]) % MOD;
}
}
return (int) dp[n];
}
}5. Code Explanation
Step 1: Modulo
final int MOD = 1000000007;The answer can become extremely large.
The problem asks us to return:
answer % 1000000007So we take modulo after every addition.
Step 2: DP Array
long[] dp = new long[n + 1];We use a one-dimensional array instead of a two-dimensional DP table.
A normal 2D solution would require:
dp[n + 1][n + 1]which requires O(n²) memory.
But we only need the previous values, so we can optimize it to:
O(n)memory.
Step 3: Base Case
dp[0] = 1;There is exactly one way to construct an empty valid string:
""So:
dp[0] = 1Step 4: Process Ones
for (int i = 1; i <= n; i++) {Here i represents the number of 1s currently available.
For example:
i = 1 → one 1
i = 2 → two 1s
i = 3 → three 1s
...Step 5: Process Zeros
for (int j = 1; j <= i; j++) {We only process:
j <= ibecause zeros can never be greater than ones.
For example, if we have:
i = 3we can have:
j = 1
j = 2
j = 3But we cannot have:
j = 4because that would mean more zeros than ones.
Step 6: DP Transition
dp[j] = (dp[j] + dp[j - 1]) % MOD;This is the most important line.
The two values represent:
dp[j] → ways from adding a 1
dp[j - 1] → ways from adding a 0Therefore:
new dp[j] = old dp[j] + old dp[j - 1]6. Dry Run for n = 3
Initially:
dp = [1, 0, 0, 0]i = 1
j = 1
dp[1] = dp[1] + dp[0]
= 0 + 1
= 1Now:
dp = [1, 1, 0, 0]i = 2
For j = 1:
dp[1] = dp[1] + dp[0]
= 1 + 1
= 2For j = 2:
dp[2] = dp[2] + dp[1]
= 0 + 2
= 2Now:
dp = [1, 2, 2, 0]i = 3
For j = 1:
dp[1] = 2 + 1 = 3For j = 2:
dp[2] = 2 + 3 = 5For j = 3:
dp[3] = 0 + 5 = 5Final:
dp = [1, 3, 5, 5]Therefore:
return (int) dp[3];returns:
57. Why Is the Answer 5?
For n = 3, we need three 1s and three 0s.
The valid strings are:
111000
110100
110010
101100
101010There are:
5valid strings.
8. Connection With Catalan Numbers
This problem is a classic Catalan Number problem.
The number of prefix-balanced binary strings with n ones and n zeros is:
$$
C_n = \frac{1}{n+1}\binom{2n}{n}
$$
The first few Catalan numbers are:
n = 0 → 1
n = 1 → 1
n = 2 → 2
n = 3 → 5
n = 4 → 14
n = 5 → 42So:
n = 2 → 2
n = 3 → 5matches the examples.
Although we could calculate the answer directly using the Catalan formula, the problem specifically expects Dynamic Programming, so the DP solution is a good fit.
9. Why Do We Need j <= i?
This is the key condition.
Consider:
100Prefix balances:
1 → 1 one, 0 zeros
10 → 1 one, 1 zero
100 → 1 one, 2 zerosAt the last prefix:
ones = 1
zeros = 2Therefore:
ones < zerosThe string is invalid.
Our DP prevents this situation by only calculating states where:
zeros <= oneswhich is:
j <= i10. Why Use long?
We use:
long[] dpinstead of:
int[] dpbecause the intermediate addition can be larger than the range of an int before modulo is applied.
This:
dp[j] + dp[j - 1]is therefore safely calculated using long.
Then we return:
(int) dp[n]because the final value has already been reduced modulo 1000000007.
11. Complexity
The outer loop runs n times.
The inner loop runs up to i times.
Therefore:
1 + 2 + 3 + ... + n = O(n²)Time Complexity
O(n²)Space Complexity
We only maintain:
long[] dpof size n + 1.
Therefore:
O(n)This exactly matches the expected complexity.
Final Takeaway
The main idea to remember is:
Treat
1as increasing the balance and0as decreasing it. A valid string must never have a negative balance.
In DP terms:
dp[i][j] = dp[i-1][j] + dp[i][j-1]with the restriction:
j <= iWe then optimize the 2D DP into a 1D array.
The final value:
dp[n]gives the number of prefix-balanced binary strings containing exactly n ones and n zeros.
Summary
This problem can be solved efficiently using Dynamic Programming. The important condition is that the number of 0s must never become greater than the number of 1s in any prefix. By keeping track of the number of ones and zeros used and ignoring invalid states where zeros > ones, we can count all valid strings. The 1D DP implementation uses O(n²) time and O(n) space, while the resulting values correspond to the well-known Catalan numbers.

Join the conversation! Your thoughts help the community grow.