Find All Possible Stable Binary Arrays I
MediumUpdated: Aug 2, 2025
Practice on:
Problem
You are given 3 positive integers zero, one, and limit.
A binary array arr is called stable if:
- The number of occurrences of 0 in
arris exactlyzero. - The number of occurrences of 1 in
arris exactlyone. - Each subarray of
arrwith a size greater thanlimitmust contain both 0 and 1.
Return the total number of stable binary arrays.
Since the answer may be very large, return it modulo 10^9 + 7.
Examples
Example 1
Input: zero = 1, one = 1, limit = 2
Output: 2
Explanation:
The two possible stable binary arrays are `[1,0]` and `[0,1]`, as both arrays
have a single 0 and a single 1, and no subarray has a length greater than 2.
Example 2
Input: zero = 1, one = 2, limit = 1
Output: 1
Explanation:
The only possible stable binary array is `[1,0,1]`.
Note that the binary arrays `[1,1,0]` and `[0,1,1]` have subarrays of length 2
with identical elements, hence, they are not stable.
Example 3
Input: zero = 3, one = 3, limit = 2
Output: 14
Explanation:
All the possible stable binary arrays are `[0,0,1,0,1,1]`, `[0,0,1,1,0,1]`,
`[0,1,0,0,1,1]`, `[0,1,0,1,0,1]`, `[0,1,0,1,1,0]`, `[0,1,1,0,0,1]`,
`[0,1,1,0,1,0]`, `[1,0,0,1,0,1]`, `[1,0,0,1,1,0]`, `[1,0,1,0,0,1]`,
`[1,0,1,0,1,0]`, `[1,0,1,1,0,0]`, `[1,1,0,0,1,0]`, and `[1,1,0,1,0,0]`.
Constraints
1 <= zero, one, limit <= 200
Solution
Method 1 – Dynamic Programming (DP with Last Placed Value)
Intuition
We want to count all binary arrays with exactly zero 0s and one 1s, such that no subarray of length > limit is all 0s or all 1s. This means we cannot have more than limit consecutive 0s or 1s. We can use DP to count the number of ways to build such arrays, keeping track of the last value placed and how many consecutive times it has been placed.
Approach
- Define
dp(z, o, last, cnt)as the number of ways to arrangezzeros andoones, where the last placed value islast(0 or 1), and it has been placedcnttimes consecutively. - Base case: if
z == 0ando == 0, return 1. - If last placed is 0 and
z > 0andcnt < limit, we can place another 0. - If last placed is 1 and
o > 0andcnt < limit, we can place another 1. - We can always switch to the other value if available, resetting the count to 1.
- Use memoization to avoid recomputation.
- Try both starting with 0 and starting with 1, sum the results.
Code
C++
class Solution {
public:
int mod = 1e9+7;
int dp(int z, int o, int last, int cnt, int limit, vector<vector<vector<vector<int>>>>& memo) {
if (z == 0 && o == 0) return 1;
if (memo[z][o][last][cnt] != -1) return memo[z][o][last][cnt];
int ans = 0;
if (last == 0) {
if (z > 0 && cnt < limit) ans = (ans + dp(z-1, o, 0, cnt+1, limit, memo)) % mod;
if (o > 0) ans = (ans + dp(z, o-1, 1, 1, limit, memo)) % mod;
} else {
if (o > 0 && cnt < limit) ans = (ans + dp(z, o-1, 1, cnt+1, limit, memo)) % mod;
if (z > 0) ans = (ans + dp(z-1, o, 0, 1, limit, memo)) % mod;
}
return memo[z][o][last][cnt] = ans;
}
int stableArrays(int zero, int one, int limit) {
vector<vector<vector<vector<int>>>> memo(zero+1, vector<vector<vector<int>>>(one+1, vector<vector<int>>(2, vector<int>(limit+2, -1))));
int ans = 0;
if (zero > 0) ans = (ans + dp(zero-1, one, 0, 1, limit, memo)) % mod;
if (one > 0) ans = (ans + dp(zero, one-1, 1, 1, limit, memo)) % mod;
return ans;
}
};
Go
func stableArrays(zero, one, limit int) int {
mod := int(1e9+7)
memo := make(map[[4]int]int)
var dp func(z, o, last, cnt int) int
dp = func(z, o, last, cnt int) int {
if z == 0 && o == 0 { return 1 }
key := [4]int{z, o, last, cnt}
if v, ok := memo[key]; ok { return v }
ans := 0
if last == 0 {
if z > 0 && cnt < limit { ans = (ans + dp(z-1, o, 0, cnt+1)) % mod }
if o > 0 { ans = (ans + dp(z, o-1, 1, 1)) % mod }
} else {
if o > 0 && cnt < limit { ans = (ans + dp(z, o-1, 1, cnt+1)) % mod }
if z > 0 { ans = (ans + dp(z-1, o, 0, 1)) % mod }
}
memo[key] = ans
return ans
}
ans := 0
if zero > 0 { ans = (ans + dp(zero-1, one, 0, 1)) % mod }
if one > 0 { ans = (ans + dp(zero, one-1, 1, 1)) % mod }
return ans
}
Java
class Solution {
int mod = (int)1e9+7;
Integer[][][][] memo;
int dp(int z, int o, int last, int cnt, int limit) {
if (z == 0 && o == 0) return 1;
if (memo[z][o][last][cnt] != null) return memo[z][o][last][cnt];
int ans = 0;
if (last == 0) {
if (z > 0 && cnt < limit) ans = (ans + dp(z-1, o, 0, cnt+1, limit)) % mod;
if (o > 0) ans = (ans + dp(z, o-1, 1, 1, limit)) % mod;
} else {
if (o > 0 && cnt < limit) ans = (ans + dp(z, o-1, 1, cnt+1, limit)) % mod;
if (z > 0) ans = (ans + dp(z-1, o, 0, 1, limit)) % mod;
}
return memo[z][o][last][cnt] = ans;
}
public int stableArrays(int zero, int one, int limit) {
memo = new Integer[zero+1][one+1][2][limit+2];
int ans = 0;
if (zero > 0) ans = (ans + dp(zero-1, one, 0, 1, limit)) % mod;
if (one > 0) ans = (ans + dp(zero, one-1, 1, 1, limit)) % mod;
return ans;
}
}
Kotlin
class Solution {
fun stableArrays(zero: Int, one: Int, limit: Int): Int {
val mod = 1_000_000_007
val memo = mutableMapOf<List<Int>, Int>()
fun dp(z: Int, o: Int, last: Int, cnt: Int): Int {
if (z == 0 && o == 0) return 1
val key = listOf(z, o, last, cnt)
memo[key]?.let { return it }
var ans = 0
if (last == 0) {
if (z > 0 && cnt < limit) ans = (ans + dp(z-1, o, 0, cnt+1)) % mod
if (o > 0) ans = (ans + dp(z, o-1, 1, 1)) % mod
} else {
if (o > 0 && cnt < limit) ans = (ans + dp(z, o-1, 1, cnt+1)) % mod
if (z > 0) ans = (ans + dp(z-1, o, 0, 1)) % mod
}
memo[key] = ans
return ans
}
var ans = 0
if (zero > 0) ans = (ans + dp(zero-1, one, 0, 1)) % mod
if (one > 0) ans = (ans + dp(zero, one-1, 1, 1)) % mod
return ans
}
}
Python
class Solution:
def stableArrays(self, zero: int, one: int, limit: int) -> int:
from functools import lru_cache
MOD = 10**9 + 7
@lru_cache(maxsize=None)
def dp(z: int, o: int, last: int, cnt: int) -> int:
if z == 0 and o == 0:
return 1
ans = 0
if last == 0:
if z > 0 and cnt < limit:
ans = (ans + dp(z-1, o, 0, cnt+1)) % MOD
if o > 0:
ans = (ans + dp(z, o-1, 1, 1)) % MOD
else:
if o > 0 and cnt < limit:
ans = (ans + dp(z, o-1, 1, cnt+1)) % MOD
if z > 0:
ans = (ans + dp(z-1, o, 0, 1)) % MOD
return ans
ans = 0
if zero > 0:
ans = (ans + dp(zero-1, one, 0, 1)) % MOD
if one > 0:
ans = (ans + dp(zero, one-1, 1, 1)) % MOD
return ans
Rust
use std::collections::HashMap;
impl Solution {
pub fn stable_arrays(zero: i32, one: i32, limit: i32) -> i32 {
fn dp(z: i32, o: i32, last: i32, cnt: i32, limit: i32, memo: &mut HashMap<(i32,i32,i32,i32), i32>) -> i32 {
if z == 0 && o == 0 { return 1; }
if let Some(&v) = memo.get(&(z,o,last,cnt)) { return v; }
let mut ans = 0;
let m = 1_000_000_007;
if last == 0 {
if z > 0 && cnt < limit { ans = (ans + dp(z-1, o, 0, cnt+1, limit, memo)) % m; }
if o > 0 { ans = (ans + dp(z, o-1, 1, 1, limit, memo)) % m; }
} else {
if o > 0 && cnt < limit { ans = (ans + dp(z, o-1, 1, cnt+1, limit, memo)) % m; }
if z > 0 { ans = (ans + dp(z-1, o, 0, 1, limit, memo)) % m; }
}
memo.insert((z,o,last,cnt), ans);
ans
}
let mut memo = HashMap::new();
let mut ans = 0;
if zero > 0 { ans = (ans + dp(zero-1, one, 0, 1, limit, &mut memo)) % 1_000_000_007; }
if one > 0 { ans = (ans + dp(zero, one-1, 1, 1, limit, &mut memo)) % 1_000_000_007; }
ans
}
}
TypeScript
class Solution {
stableArrays(zero: number, one: number, limit: number): number {
const MOD = 1e9 + 7;
const memo = new Map<string, number>();
function dp(z: number, o: number, last: number, cnt: number): number {
if (z === 0 && o === 0) return 1;
const key = `${z},${o},${last},${cnt}`;
if (memo.has(key)) return memo.get(key)!;
let ans = 0;
if (last === 0) {
if (z > 0 && cnt < limit) ans = (ans + dp(z-1, o, 0, cnt+1)) % MOD;
if (o > 0) ans = (ans + dp(z, o-1, 1, 1)) % MOD;
} else {
if (o > 0 && cnt < limit) ans = (ans + dp(z, o-1, 1, cnt+1)) % MOD;
if (z > 0) ans = (ans + dp(z-1, o, 0, 1)) % MOD;
}
memo.set(key, ans);
return ans;
}
let ans = 0;
if (zero > 0) ans = (ans + dp(zero-1, one, 0, 1)) % MOD;
if (one > 0) ans = (ans + dp(zero, one-1, 1, 1)) % MOD;
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(zero * one * limit * 2), as each state is visited once. - 🧺 Space complexity:
O(zero * one * limit * 2), for memoization.