Talentd
FleetCode
Make and follow sheets.Sign in

Find All Possible Stable Binary Arrays II solution and explanation

HardDynamic ProgrammingPrefix Sum8 min read58.4% acceptanceUpdated 9 Apr 2026
Find All Possible Stable Binary Arrays II | Derive From Part I | Detailed | Leetcode 3130 | MIKcodestorywithMIK · 25:33 · 10K viewsWatch on YouTube
9 more videos on this problem
  1. Find All Possible Stable Binary Arrays II | Derive From Part I | Detailed | Leetcode 3130 | MIKcodestorywithMIK · 25:33 · 10K views
  2. 3130 & 3129 Find All Possible Stable Binary Arrays II | DP | Prefix Sums | Sliding WindowAryan Mittal · 55:54 · 5K views
  3. Find All Possible Stable Binary Arrays I & II - Leetcode Biweekly Contest 129 | Abhinav AwasthiAbhinav Awasthi · 21:18 · 3K views
  4. 3130. Find All Possible Stable Binary Arrays II | Leetcode Daily - PythonLeetcode Daily · 10:06 · 825 views
  5. 3130. Find All Possible Stable Binary Arrays II (Leetcode Hard)Programming Live with Larry · 48:25 · 538 views
  6. Daily Leetcode #2170: Mar 10, 2026 - 3130. Find All Possible Stable Binary Arrays IIProgramming Live with Larry · 36:20 · 505 views
  7. 3130 Find All Possible Stable Binary Arrays II | Visualized 🤯Code Crusaders · 9:14 · 439 views
  8. leetcode 3130 | Find All Possible Stable Binary Arrays II | Dynamic Programming | Leetcode POTD| DSACode With Vick · 15:20 · 341 views
  9. Find All Possible Stable Binary Arrays II | LeetCode 3130 - Pythonimpoldev · 1:07 · 258 views
  10. 3130. Find All Possible Stable Binary Arrays I and II | Leetcode Daily ChallengeEye on AI and DSA · 27:33 · 201 views

The 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 arr is exactly zero.
  • The number of occurrences of 1 in arr is exactly one.
  • Each subarray of arr with a size greater than limit must contain both 0 and 1.

Return the total number of stable binary arrays.

Since the answer may be very large, return it modulo 109 + 7.

Example 1:

Input: zero = 1, one = 1, limit = 2

Output: 2

Explanation:

The two possible stable binary arrays are [1,0] and [0,1].

Example 2:

Input: zero = 1, one = 2, limit = 1

Output: 1

Explanation:

The only possible stable binary array is [1,0,1].

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 <= 1000

Approach overview

Problem Overview: Count the number of binary arrays that use exactly zero zeros and one ones while ensuring no more than limit identical values appear consecutively. The result must include every valid arrangement that satisfies both the count constraint and the stability rule.

Approach 1: Hash Map Memoization (Top-Down DP) (Time: O(zero * one * limit), Space: O(zero * one * limit))

Model the problem as dynamic programming with memoization. Each state represents how many zeros and ones remain, what the last placed value was, and how long the current streak is. A recursive function explores placing either a 0 or 1 if doing so does not exceed the limit. Results for states like (z, o, last, streak) are cached in a hash map so repeated subproblems are computed once. This avoids exponential recursion and turns the search into a bounded DP over all valid states. The approach is straightforward to implement and clearly expresses the constraint logic, making it a good first solution when exploring dynamic programming problems with state transitions.

Approach 2: Sorting + Prefix Sum Optimized DP (Time: O((zero + one) log (zero + one) + zero * one), Space: O(zero * one))

A more optimized solution focuses on counting sequences without explicitly tracking every streak length. Instead of iterating over each possible extension one step at a time, prefix sums aggregate counts of valid transitions. You compute how many ways exist to end with a zero or one for each combination of used zeros and ones. Prefix ranges help subtract invalid configurations where the streak would exceed limit. Sorting can be used to normalize block expansions and process transitions in consistent order while prefix sums enable constant-time range queries. This reduces the number of repeated calculations and converts the naive streak iteration into efficient range updates, a common optimization technique in prefix sum based DP counting problems.

The DP table typically tracks two states: arrays ending in 0 and arrays ending in 1. For each cell, transitions add valid contributions from previous cells while subtracting sequences that would violate the consecutive limit. Prefix sums make these additions and removals constant-time instead of iterating over every possible streak length.

Recommended for interviews: Start with the memoized DP using a hash map to show you understand the state space and constraint handling. Interviewers usually expect the optimized DP with prefix sums afterward because it improves performance from streak-based iteration to aggregated transitions. Demonstrating both approaches shows strong command of DP state design and optimization techniques.

Approach 1: Approach 1: Using a Hash Map

This approach utilizes a hash map to store elements as keys and their frequencies as values. It helps in quick look-up and insertion, providing an efficient way to solve the problem.

arr = [2, 2, 3, 1, 2, 3, 1]
frequency = {}

for num in arr:
   if num in frequency:
      frequency[num] += 1
   else:
      frequency[num] = 1

print(f'Frequency of 2: {frequency[2]}')
print(f'Frequency of 3: {frequency[3]}')
print(f'Frequency of 1: {frequency[1]}')
import java.util.HashMap;

public class Main {
   public static void main(String[] args) {
      int[] arr = {2, 2, 3, 1, 2, 3, 1};
      HashMap<Integer, Integer> frequency = new HashMap<>();

      for (int i : arr) {
         frequency.put(i, frequency.getOrDefault(i, 0) + 1);
      }

      System.out.println("Frequency of 2: " + frequency.get(2));
      System.out.println("Frequency of 3: " + frequency.get(3));
      System.out.println("Frequency of 1: " + frequency.get(1));
   }
}
#include <iostream>
#include <unordered_map>

int main() {
   std::unordered_map<int, int> frequency;
   int arr[] = {2, 2, 3, 1, 2, 3, 1};
   int n = sizeof(arr) / sizeof(arr[0]);

   for (int i = 0; i < n; ++i) {
      frequency[arr[i]]++;
   }

   std::cout << "Frequency of 2: " << frequency[2] << std::endl;
   std::cout << "Frequency of 3: " << frequency[3] << std::endl;
   std::cout << "Frequency of 1: " << frequency[1] << std::endl;

   return 0;
}
let arr = [2, 2, 3, 1, 2, 3, 1];
let frequency = {};

arr.forEach(num => {
   frequency[num] = (frequency[num] || 0) + 1;
});

console.log('Frequency of 2:', frequency[2]);
console.log('Frequency of 3:', frequency[3]);
console.log('Frequency of 1:', frequency[1]);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TABLE_SIZE 100

typedef struct Pair {
   int key;
   int value;
   struct Pair* next;
} Pair;

typedef struct HashMap {
   Pair* table[TABLE_SIZE];
} HashMap;

int hash(int key) {
   return key % TABLE_SIZE;
}

HashMap* create_hash_map() {
   HashMap* map = (HashMap*)malloc(sizeof(HashMap));
   memset(map, 0, sizeof(HashMap));
   return map;
}

void put(HashMap* map, int key, int value) {
   int index = hash(key);
   Pair* new_pair = (Pair*)malloc(sizeof(Pair));
   new_pair->key = key;
   new_pair->value = value;
   new_pair->next = map->table[index];
   map->table[index] = new_pair;
}

int get(HashMap* map, int key) {
   int index = hash(key);
   Pair* pair = map->table[index];
   while (pair) {
      if (pair->key == key) return pair->value;
      pair = pair->next;
   }
   return -1;  // If not found
}

void increment(HashMap* map, int key) {
   int index = hash(key);
   Pair* pair = map->table[index];
   while (pair) {
      if (pair->key == key) {
         pair->value++;
         return;
      }
      pair = pair->next;
   }
   put(map, key, 1);
}

int main() {
   int arr[] = {2, 2, 3, 1, 2, 3, 1};
   int n = sizeof(arr) / sizeof(arr[0]);
   HashMap* map = create_hash_map();

   for (int i = 0; i < n; i++) {
      increment(map, arr[i]);
   }

   // Example usage: print the frequency of 2 and other elements
   printf("Frequency of 2: %d\n", get(map, 2));
   printf("Frequency of 3: %d\n", get(map, 3));
   printf("Frequency of 1: %d\n", get(map, 1));

   // Free memory omitted for simplicity
   return 0;
}
using System;
using System.Collections.Generic;

class Program {
   static void Main() {
      int[] arr = {2, 2, 3, 1, 2, 3, 1};
      Dictionary<int, int> frequency = new Dictionary<int, int>();

      foreach (int num in arr) {
         if (frequency.ContainsKey(num)) {
            frequency[num]++;
         } else {
            frequency[num] = 1;
         }
      }

      Console.WriteLine("Frequency of 2: " + frequency[2]);
      Console.WriteLine("Frequency of 3: " + frequency[3]);
      Console.WriteLine("Frequency of 1: " + frequency[1]);
   }
}

This Python solution uses a dictionary to store the frequency of each element in the input list. It iterates through each element, updating the count in the dictionary. The dictionary provides constant average time complexity for insertion and look-up operations.

Complexity

Time Complexity: O(n), where n is the number of elements in the list.
Space Complexity: O(n) for storing the frequency of elements in the dictionary.

Try this approach in the editor

Approach 2: Approach 2: Using Sorting

This approach involves sorting the array first, which groups identical elements together. After sorting, a single pass through the array is sufficient to count the frequencies of all elements.

arr = [2, 2, 3, 1, 2, 3, 1]

arr.sort()

current_count = 1
for i in range(1, len(arr)):
   if arr[i] == arr[i - 1]:
      current_count += 1
   else:
      print(f'Element: {arr[i - 1]}, Frequency: {current_count}')
      current_count = 1
print(f'Element: {arr[-1]}, Frequency: {current_count}')
import java.util.Arrays;

public class Main {
   public static void frequencyCount(int[] arr) {
      Arrays.sort(arr);

      int currentCount = 1;
      for (int i = 1; i < arr.length; i++) {
         if (arr[i] == arr[i - 1]) {
            currentCount++;
         } else {
            System.out.println("Element: " + arr[i - 1] + ", Frequency: " + currentCount);
            currentCount = 1;
         }
      }
      System.out.println("Element: " + arr[arr.length - 1] + ", Frequency: " + currentCount);
   }

   public static void main(String[] args) {
      int[] arr = {2, 2, 3, 1, 2, 3, 1};
      frequencyCount(arr);
   }
}
#include <iostream>
#include <algorithm>

void frequency_count(int arr[], int n) {
   std::sort(arr, arr + n);

   int current_count = 1;
   for (int i = 1; i < n; ++i) {
      if (arr[i] == arr[i - 1]) {
         ++current_count;
      } else {
         std::cout << "Element: " << arr[i - 1] << ", Frequency: " << current_count << std::endl;
         current_count = 1;
      }
   }
   std::cout << "Element: " << arr[n - 1] << ", Frequency: " << current_count << std::endl;
}

int main() {
   int arr[] = {2, 2, 3, 1, 2, 3, 1};
   int n = sizeof(arr) / sizeof(arr[0]);
   frequency_count(arr, n);

   return 0;
}
let arr = [2, 2, 3, 1, 2, 3, 1];

arr.sort((a, b) => a - b);

let currentCount = 1;
for (let i = 1; i < arr.length; i++) {
   if (arr[i] === arr[i - 1]) {
      currentCount++;
   } else {
      console.log(`Element: ${arr[i - 1]}, Frequency: ${currentCount}`);
      currentCount = 1;
   }
}
console.log(`Element: ${arr[arr.length - 1]}, Frequency: ${currentCount}`);
#include <stdio.h>
#include <stdlib.h>

int cmpfunc(const void* a, const void* b) {
   return (*(int*)a - *(int*)b);
}

void frequency_count(int arr[], int n) {
   qsort(arr, n, sizeof(int), cmpfunc);

   int current_count = 1;
   for (int i = 1; i < n; i++) {
      if (arr[i] == arr[i - 1]) {
         current_count++;
      } else {
         printf("Element: %d, Frequency: %d\n", arr[i - 1], current_count);
         current_count = 1;
      }
   }
   printf("Element: %d, Frequency: %d\n", arr[n - 1], current_count);
}

int main() {
   int arr[] = {2, 2, 3, 1, 2, 3, 1};
   int n = sizeof(arr) / sizeof(arr[0]);
   frequency_count(arr, n);
   return 0;
}
using System;

class Program {
   static void FrequencyCount(int[] arr) {
      Array.Sort(arr);

      int currentCount = 1;
      for (int i = 1; i < arr.Length; i++) {
         if (arr[i] == arr[i - 1]) {
            currentCount++;
         } else {
            Console.WriteLine($"Element: {arr[i - 1]}, Frequency: {currentCount}");
            currentCount = 1;
         }
      }
      Console.WriteLine($"Element: {arr[arr.Length - 1]}, Frequency: {currentCount}");
   }

   static void Main() {
      int[] arr = {2, 2, 3, 1, 2, 3, 1};
      FrequencyCount(arr);
   }
}

In this Python solution, the list is first sorted using the built-in sort function. After sorting, a single pass through the list allows for simple calculation and display of each unique element’s frequency.

Complexity

Time Complexity: O(n log n) for sorting, and O(n) for the iteration post-sorting.
Space Complexity: O(1) if the sort is done in-place or O(n) if not.

Try this approach in the editor

Approach 3: Memoization Search

We design a function dfs(i, j, k) to represent the number of stable binary arrays that satisfy the problem conditions when there are i 0s and j 1s left, and the next number to be filled is k. The answer is dfs(zero, one, 0) + dfs(zero, one, 1).

The calculation process of the function dfs(i, j, k) is as follows:

  • If i < 0 or j < 0, return 0.
  • If i = 0, return 1 when k = 1 and j leq limit, otherwise return 0.
  • If j = 0, return 1 when k = 0 and i leq limit, otherwise return 0.
  • If k = 0, we consider the case where the previous number is 0, dfs(i - 1, j, 0), and the case where the previous number is 1, dfs(i - 1, j, 1). If the previous number is 0, it may cause more than limit 0s in the subarray, i.e., the situation where the limit + 1
func numberOfStableArrays(zero int, one int, limit int) int {
	const mod int = 1e9 + 7
	f := make([][][2]int, zero+1)
	for i := range f {
		f[i] = make([][2]int, one+1)
		for j := range f[i] {
			f[i][j] = [2]int{-1, -1}
		}
	}
	var dfs func(i, j, k int) int
	dfs = func(i, j, k int) int {
		if i < 0 || j < 0 {
			return 0
		}
		if i == 0 {
			if k == 1 && j <= limit {
				return 1
			}
			return 0
		}
		if j == 0 {
			if k == 0 && i <= limit {
				return 1
			}
			return 0
		}
		res := &f[i][j][k]
		if *res != -1 {
			return *res
		}
		if k == 0 {
			*res = (dfs(i-1, j, 0) + dfs(i-1, j, 1) - dfs(i-limit-1, j, 1) + mod) % mod
		} else {
			*res = (dfs(i, j-1, 0) + dfs(i, j-1, 1) - dfs(i, j-limit-1, 0) + mod) % mod
		}
		return *res
	}
	return (dfs(zero, one, 0) + dfs(zero, one, 1)) % mod
}
impl Solution {
    pub fn number_of_stable_arrays(zero: i32, one: i32, limit: i32) -> i32 {
        const MOD: i64 = 1_000_000_007;

        fn dfs(
            i: i32,
            j: i32,
            k: usize,
            limit: i32,
            f: &mut Vec<Vec<[i64; 2]>>,
        ) -> i64 {
            if i < 0 || j < 0 {
                return 0;
            }

            if i == 0 {
                return if k == 1 && j <= limit { 1 } else { 0 };
            }

            if j == 0 {
                return if k == 0 && i <= limit { 1 } else { 0 };
            }

            let (iu, ju) = (i as usize, j as usize);

            if f[iu][ju][k] != -1 {
                return f[iu][ju][k];
            }

            let res = if k == 0 {
                (
                    dfs(i - 1, j, 0, limit, f)
                    + dfs(i - 1, j, 1, limit, f)
                    - dfs(i - limit - 1, j, 1, limit, f)
                    + MOD
                ) % MOD
            } else {
                (
                    dfs(i, j - 1, 0, limit, f)
                    + dfs(i, j - 1, 1, limit, f)
                    - dfs(i, j - limit - 1, 0, limit, f)
                    + MOD
                ) % MOD
            };

            f[iu][ju][k] = res;
            res
        }

        let mut f = vec![vec![[-1_i64; 2]; (one + 1) as usize]; (zero + 1) as usize];

        ((dfs(zero, one, 0, limit, &mut f) + dfs(zero, one, 1, limit, &mut f)) % MOD) as i32
    }
}
Try this approach in the editor

Approach 4: Dynamic Programming

We can also convert the memoization search of Solution 1 into dynamic programming.

We define f[i][j][k] as the number of stable binary arrays using i 0s and j 1s, and the last number is k. So the answer is f[zero][one][0] + f[zero][one][1].

Initially, we have f[i][0][0] = 1, where 1 leq i leq min(limit, zero); and f[0][j][1] = 1, where 1 leq j leq min(limit, one).

The state transition equation is as follows:

  • f[i][j][0] = f[i - 1][j][0] + f[i - 1][j][1] - f[i - limit - 1][j][1].
  • f[i][j][1] = f[i][j - 1][0] + f[i][j - 1][1] - f[i][j - limit - 1][0].

The time complexity is O(zero times one), and the space complexity is O(zero times one).

function numberOfStableArrays(zero: number, one: number, limit: number): number {
    const mod = 1e9 + 7;
    const f: number[][][] = Array.from({ length: zero + 1 }, () =>
        Array.from({ length: one + 1 }, () => [0, 0]),
    );

    for (let i = 1; i <= Math.min(limit, zero); i++) {
        f[i][0][0] = 1;
    }
    for (let j = 1; j <= Math.min(limit, one); j++) {
        f[0][j][1] = 1;
    }

    for (let i = 1; i <= zero; i++) {
        for (let j = 1; j <= one; j++) {
            const x = i - limit - 1 < 0 ? 0 : f[i - limit - 1][j][1];
            const y = j - limit - 1 < 0 ? 0 : f[i][j - limit - 1][0];
            f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1] - x + mod) % mod;
            f[i][j][1] = (f[i][j - 1][0] + f[i][j - 1][1] - y + mod) % mod;
        }
    }

    return (f[zero][one][0] + f[zero][one][1]) % mod;
}
func numberOfStableArrays(zero int, one int, limit int) int {
	const mod int = 1e9 + 7
	f := make([][][2]int, zero+1)
	for i := range f {
		f[i] = make([][2]int, one+1)
	}
	for i := 1; i <= min(zero, limit); i++ {
		f[i][0][0] = 1
	}
	for j := 1; j <= min(one, limit); j++ {
		f[0][j][1] = 1
	}
	for i := 1; i <= zero; i++ {
		for j := 1; j <= one; j++ {
			f[i][j][0] = (f[i-1][j][0] + f[i-1][j][1]) % mod
			if i-limit-1 >= 0 {
				f[i][j][0] = (f[i][j][0] - f[i-limit-1][j][1] + mod) % mod
			}
			f[i][j][1] = (f[i][j-1][0] + f[i][j-1][1]) % mod
			if j-limit-1 >= 0 {
				f[i][j][1] = (f[i][j][1] - f[i][j-limit-1][0] + mod) % mod
			}
		}
	}
	return (f[zero][one][0] + f[zero][one][1]) % mod
}
impl Solution {
    pub fn number_of_stable_arrays(zero: i32, one: i32, limit: i32) -> i32 {
        let mod_: i64 = 1_000_000_007;

        let zero = zero as usize;
        let one = one as usize;
        let limit = limit as usize;

        let mut f = vec![vec![[0_i64; 2]; one + 1]; zero + 1];

        for i in 1..=zero.min(limit) {
            f[i][0][0] = 1;
        }

        for j in 1..=one.min(limit) {
            f[0][j][1] = 1;
        }

        for i in 1..=zero {
            for j in 1..=one {
                let x = if i > limit { f[i - limit - 1][j][1] } else { 0 };
                let y = if j > limit { f[i][j - limit - 1][0] } else { 0 };

                f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1] - x + mod_) % mod_;
                f[i][j][1] = (f[i][j - 1][0] + f[i][j - 1][1] - y + mod_) % mod_;
            }
        }

        ((f[zero][one][0] + f[zero][one][1]) % mod_) as i32
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Approach 1: Using a Hash Map

Time Complexity: O(n), where n is the number of elements in the list.
Space Complexity: O(n) for storing the frequency of elements in the dictionary.

Approach 2: Using Sorting

Time Complexity: O(n log n) for sorting, and O(n) for the iteration post-sorting.
Space Complexity: O(1) if the sort is done in-place or O(n) if not.

Memoization Search–
Dynamic Programming–

Complexity analysis

ApproachTimeSpaceWhen to Use
Hash Map Memoized DPO(zero * one * limit)O(zero * one * limit)When building the solution step‑by‑step or explaining the full DP state in interviews
Sorting + Prefix Sum DPO((zero + one) log (zero + one) + zero * one)O(zero * one)Preferred optimized solution when counting large numbers of sequences efficiently

Frequently asked questions

Is Find All Possible Stable Binary Arrays II easy or hard?

Find All Possible Stable Binary Arrays II is categorized as a Hard problem. It requires designing a multi‑state dynamic programming solution and then optimizing transitions with prefix sums to handle large constraints efficiently.

Find All Possible Stable Binary Arrays II Python/Java solution

The solution can be implemented in Python or Java using DP arrays that track counts of sequences ending with 0 or 1. Prefix sums optimize transitions by quickly computing valid ranges of previous states. The same algorithm translates directly to C++, C#, and JavaScript.

How to solve Find All Possible Stable Binary Arrays II in O(n)?

You approach near-linear complexity relative to the DP state size using prefix sums. Instead of iterating through every possible streak length up to the limit, prefix sums aggregate valid ranges of transitions and subtract invalid ones in constant time. This reduces the state transition cost to O(1) per DP cell.

What is the best approach for Find All Possible Stable Binary Arrays II?

The most efficient solution uses dynamic programming with prefix sum optimization. The DP tracks how many arrays can end with 0 or 1 for each count of used zeros and ones, while prefix sums subtract sequences that exceed the consecutive limit. This reduces repeated streak calculations and runs in O(zero * one) time.

Is Find All Possible Stable Binary Arrays II asked at Google/Amazon/Meta?

Problems involving constrained binary sequences and DP counting frequently appear in interviews at companies like Google, Amazon, and Meta. Variants that limit consecutive elements or count valid arrangements are common because they test dynamic programming design and optimization skills.

What data structure is used in Find All Possible Stable Binary Arrays II?

The main structure is a dynamic programming table combined with prefix sums for fast range calculations. A hash map may also be used in the memoized version to cache recursive states such as remaining zeros, remaining ones, last element, and current streak length.

What is the time complexity of Find All Possible Stable Binary Arrays II?

The optimized dynamic programming solution runs in O(zero * one) time with prefix sums and uses O(zero * one) space. A straightforward memoized recursion using a hash map may take O(zero * one * limit) time because it explicitly tracks streak length in the state.

Comments

Now write it yourselfClose this page and solve Find All Possible Stable Binary Arrays II in the editor, without looking.
Practise Find All Possible Stable Binary Arrays II