Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to count maximum number of strings we can generate from list of words and letter counts in python
Suppose we have a list of strings where each string contains only letters "A"s and "B"s. We have two values a and b. We have to find the maximum number of strings that can be formed using at most a number of "A"s and at most b number of "B"s, without reusing strings.
So, if the input is like strings = ["AAABB", "AABB", "AA", "BB"], a = 4, b = 2, then the output will be 2, as we can take the strings using 4 "A"s and 2 "B"s: ["AABB", "AA"].
Approach
To solve this, we will follow these steps ?
- Create pairs of (A_count, B_count) for each string
- Use dynamic programming with a dictionary to track maximum strings possible for each remaining (a, b) state
- For each string, update all possible states by trying to include it
- Return the maximum count from all final states
Example
Let's see the implementation with a step-by-step approach ?
class Solution:
def solve(self, strings, a, b):
# Step 1: Create pairs of (A_count, B_count) for each string
pairs = []
for w in strings:
A = w.count("A")
B = len(w) - A
pairs.append((A, B))
# Step 2: Initialize DP with base state (a, b) -> 0 strings used
ans = {(a, b): 0}
# Step 3: For each string, try to include it in all possible states
for A, B in pairs:
temp = dict(ans)
for (temp_a, temp_b), wc in ans.items():
if temp_a >= A and temp_b >= B:
rem = (temp_a - A, temp_b - B)
temp[rem] = max(temp.get(rem, 0), wc + 1)
ans = temp
# Step 4: Return maximum strings formed
return max(ans.values())
# Test the solution
ob = Solution()
strings = ["AAABB", "AABB", "AA", "BB"]
a = 4
b = 2
result = ob.solve(strings, a, b)
print(f"Maximum strings that can be formed: {result}")
Maximum strings that can be formed: 2
How It Works
The algorithm works by maintaining a dictionary where keys represent remaining letters (remaining_A, remaining_B) and values represent the maximum number of strings formed to reach that state.
# Let's trace through the example step by step
strings = ["AAABB", "AABB", "AA", "BB"]
a, b = 4, 2
# Step 1: Count A's and B's in each string
pairs = []
for string in strings:
A_count = string.count("A")
B_count = len(string) - A_count
pairs.append((A_count, B_count))
print(f"'{string}' -> A: {A_count}, B: {B_count}")
print(f"\nPairs: {pairs}")
'AAABB' -> A: 3, B: 2 'AABB' -> A: 2, B: 2 'AA' -> A: 2, B: 0 'BB' -> A: 0, B: 2 Pairs: [(3, 2), (2, 2), (2, 0), (0, 2)]
Alternative Approach Using Recursion
Here's a more intuitive recursive approach with memoization ?
def max_strings_recursive(strings, a, b):
def count_letters(s):
return s.count("A"), len(s) - s.count("A")
def backtrack(index, remaining_a, remaining_b):
if index == len(strings):
return 0
# Option 1: Skip current string
result = backtrack(index + 1, remaining_a, remaining_b)
# Option 2: Include current string if possible
need_a, need_b = count_letters(strings[index])
if remaining_a >= need_a and remaining_b >= need_b:
result = max(result, 1 + backtrack(index + 1, remaining_a - need_a, remaining_b - need_b))
return result
return backtrack(0, a, b)
# Test the recursive approach
strings = ["AAABB", "AABB", "AA", "BB"]
result = max_strings_recursive(strings, 4, 2)
print(f"Maximum strings (recursive): {result}")
Maximum strings (recursive): 2
Comparison
| Approach | Time Complexity | Space Complexity | Best For |
|---|---|---|---|
| Dynamic Programming | O(n × a × b) | O(a × b) | Larger inputs |
| Recursive (with memoization) | O(2^n) | O(n) | Understanding logic |
Conclusion
The dynamic programming approach efficiently solves the problem by tracking all possible states of remaining letters. For each string, we update all feasible states to maximize the count of strings that can be formed.
