Watch 10 video solutions for Ones and Zeroes, a medium level problem involving Array, String, Dynamic Programming. This walkthrough by Algorithms Made Easy has 18,315 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
You are given an array of binary strings strs and two integers m and n.
Return the size of the largest subset of strs such that there are at most m 0's and n 1's in the subset.
A set x is a subset of a set y if all elements of x are also elements of y.
Example 1:
Input: strs = ["10","0001","111001","1","0"], m = 5, n = 3
Output: 4
Explanation: The largest subset with at most 5 0's and 3 1's is {"10", "0001", "1", "0"}, so the answer is 4.
Other valid but smaller subsets include {"0001", "1"} and {"10", "1", "0"}.
{"111001"} is an invalid subset because it contains 4 1's, greater than the maximum of 3.
Example 2:
Input: strs = ["10","0","1"], m = 1, n = 1
Output: 2
Explanation: The largest subset is {"0", "1"}, so the answer is 2.
Constraints:
1 <= strs.length <= 6001 <= strs[i].length <= 100strs[i] consists only of digits '0' and '1'.1 <= m, n <= 100Problem Overview: You get an array of binary strings and two limits: m zeros and n ones. The task is to choose the largest subset of strings such that the total number of zeros used does not exceed m and the total number of ones does not exceed n.
The constraint immediately resembles a capacity problem. Each string “costs” a certain number of zeros and ones, and the goal is to maximize how many strings you include without exceeding those limits.
Approach 1: Memoized Recursive (Top-Down DP) (Time: O(k*m*n), Space: O(k*m*n))
Treat each string as a decision point: include it or skip it. First count how many zeros and ones the current string contains. Then recursively explore two choices: skip the string and move to the next index, or include it if the remaining capacity allows. Memoization stores results for states defined by (index, remainingZeros, remainingOnes). This prevents recomputation of overlapping subproblems.
The recursion behaves exactly like a 0/1 knapsack. Each string is an item with two resource costs. Memoization ensures every state is solved once, which keeps the runtime manageable. This approach is intuitive when thinking recursively and helps visualize the decision tree.
Approach 2: Dynamic Programming (0/1 Knapsack) (Time: O(k*m*n), Space: O(m*n))
The iterative dynamic programming version compresses the state into a 2D table dp[i][j], representing the maximum number of strings you can form using i zeros and j ones. For each string, compute its zero and one counts. Then iterate the DP table backwards (from m → zeros and n → ones) to update the state.
The reverse iteration is critical. It ensures each string is used at most once, preserving the 0/1 knapsack behavior. The update rule becomes: dp[i][j] = max(dp[i][j], 1 + dp[i-zeros][j-ones]). This approach eliminates the recursion stack and reduces memory from three dimensions to two.
This problem sits at the intersection of Dynamic Programming, Array, and String processing. The key step is converting each string into resource counts, which turns the problem into a classic capacity optimization.
Recommended for interviews: The bottom-up dynamic programming solution. Interviewers expect candidates to recognize the 0/1 knapsack pattern and build a 2D DP table with reverse iteration. Discussing the recursive memoized version first shows problem decomposition skills, while implementing the iterative DP demonstrates strong dynamic programming fundamentals.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Memoized Recursive (Top-Down DP) | O(k*m*n) | O(k*m*n) | When reasoning about include/exclude decisions is easier with recursion |
| Dynamic Programming (Bottom-Up Knapsack) | O(k*m*n) | O(m*n) | Best general solution; optimal memory usage and common interview expectation |