Given 3 characters 'a', 'b', 'c', find the number of strings of length n that can be formed from these 3 characters. Given that :
- We can use ‘a’ as many times as we want.
- ‘b’ maximum once
- ‘c’ maximum twice.
Examples:
Input: n = 2
Output: 8
Explanation: There are total 8 possible strings and these are: [aa, ab, ba, ac,ca, bc, cb, cc].Input: n = 3
Output: 19
Explanation: There are total 19 possible strings.
Table of Content
[Naive Recursive Approach] Generating All Valid Strings - O(3ⁿ) Time and O(n) Space
The idea is to recursively build all possible strings of length
nwhile keeping track of the remaining number of'b'and'c'characters that can still be used.
- Start with at most
1occurrence of'b' and at most2occurrences of'c' - For each position: Place
'a', place'b'if any'b'remains and place'c'if any'c'remains - Recursively fill the remaining positions
- When length becomes
0, return1
#include <bits/stdc++.h>
using namespace std;
// Returns number of valid strings
int solve(int n, int b, int c)
{
// Successfully formed a valid string
if (n == 0)
return 1;
int ans = 0;
// Place 'a'
ans += solve(n - 1, b, c);
// Place 'b'
if (b > 0)
ans += solve(n - 1, b - 1, c);
// Place 'c'
if (c > 0)
ans += solve(n - 1, b, c - 1);
return ans;
}
int noOfString(int n)
{
return solve(n, 1, 2);
}
int main()
{
int n = 3;
cout << noOfString(n);
return 0;
}
// Java program to count number of valid strings
import java.util.*;
class GfG {
// Returns number of valid strings
static int solve(int n, int b, int c) {
// Successfully formed a valid string
if (n == 0)
return 1;
int ans = 0;
// Place 'a'
ans += solve(n - 1, b, c);
// Place 'b'
if (b > 0)
ans += solve(n - 1, b - 1, c);
// Place 'c'
if (c > 0)
ans += solve(n - 1, b, c - 1);
return ans;
}
static int noOfString(int n) {
return solve(n, 1, 2);
}
public static void main(String[] args) {
int n = 3;
System.out.println(noOfString(n));
}
}
# Python program to count number of valid strings
# Returns number of valid strings
def solve(n, b, c):
# Successfully formed a valid string
if n == 0:
return 1
ans = 0
# Place 'a'
ans += solve(n - 1, b, c)
# Place 'b'
if b > 0:
ans += solve(n - 1, b - 1, c)
# Place 'c'
if c > 0:
ans += solve(n - 1, b, c - 1)
return ans
def noOfString(n):
return solve(n, 1, 2)
# Driver code
if __name__ == "__main__":
n = 3
print(noOfString(n))
// C# program to count number of valid strings
using System;
class GfG {
// Returns number of valid strings
static int solve(int n, int b, int c) {
// Successfully formed a valid string
if (n == 0)
return 1;
int ans = 0;
// Place 'a'
ans += solve(n - 1, b, c);
// Place 'b'
if (b > 0)
ans += solve(n - 1, b - 1, c);
// Place 'c'
if (c > 0)
ans += solve(n - 1, b, c - 1);
return ans;
}
static int noOfString(int n) {
return solve(n, 1, 2);
}
static void Main(string[] args) {
int n = 3;
Console.WriteLine(noOfString(n));
}
}
// JavaScript program to count number of valid strings
// Returns number of valid strings
function solve(n, b, c) {
// Successfully formed a valid string
if (n === 0)
return 1;
let ans = 0;
// Place 'a'
ans += solve(n - 1, b, c);
// Place 'b'
if (b > 0)
ans += solve(n - 1, b - 1, c);
// Place 'c'
if (c > 0)
ans += solve(n - 1, b, c - 1);
return ans;
}
function noOfString(n) {
return solve(n, 1, 2);
}
// Driver code
const n = 3;
console.log(noOfString(n));
Output
19
[Tabulation Approach] Using Bottom Up DP - O(n) Time and O(n) Space
The idea is to build the answer iteratively instead of using recursion. A DP state
dp[len][b][c]stores the number of valid strings that can be formed with remaining lengthlen,boccurrences of'b', andcoccurrences of'c'available. Starting from the base case where the remaining length is0, the table is filled for increasing lengths by considering the three possible choices: place'a', place'b'(if available), or place'c'(if available). The final answer is obtained from the state representing lengthnwith one'b'and two'c'characters available.
- Create a 3D DP table
dp[len][b][c] - Initialize base cases,
dp[0][b][c] = 1for all validbandc - For each length from
1ton, add ways by placing'a', add ways by placing'b'ifb > 0 and add ways by placing'c'ifc > 0 - Return
dp[n][1][2]
#include <bits/stdc++.h>
using namespace std;
int noOfString(int n)
{
vector<vector<vector<int>>> dp(n + 1, vector<vector<int>>(2, vector<int>(3, 0)));
// Base case
for (int b = 0; b <= 1; b++)
{
for (int c = 0; c <= 2; c++)
{
dp[0][b][c] = 1;
}
}
for (int len = 1; len <= n; len++)
{
for (int b = 0; b <= 1; b++)
{
for (int c = 0; c <= 2; c++)
{
// Place 'a'
dp[len][b][c] += dp[len - 1][b][c];
// Place 'b'
if (b > 0)
dp[len][b][c] += dp[len - 1][b - 1][c];
// Place 'c'
if (c > 0)
dp[len][b][c] += dp[len - 1][b][c - 1];
}
}
}
return dp[n][1][2];
}
int main()
{
int n = 3;
cout << noOfString(n);
return 0;
}
// Java program to count number of valid strings using iterative DP
import java.util.*;
class GfG {
static int noOfString(int n) {
int[][][] dp = new int[n + 1][2][3];
// Base case
for (int b = 0; b <= 1; b++) {
for (int c = 0; c <= 2; c++) {
dp[0][b][c] = 1;
}
}
for (int len = 1; len <= n; len++) {
for (int b = 0; b <= 1; b++) {
for (int c = 0; c <= 2; c++) {
// Place 'a'
dp[len][b][c] += dp[len - 1][b][c];
// Place 'b'
if (b > 0)
dp[len][b][c] += dp[len - 1][b - 1][c];
// Place 'c'
if (c > 0)
dp[len][b][c] += dp[len - 1][b][c - 1];
}
}
}
return dp[n][1][2];
}
public static void main(String[] args) {
int n = 3;
System.out.println(noOfString(n));
}
}
# Python program to count number of valid strings using iterative DP
def noOfString(n):
# dp[len][b][c]
dp = [[[0] * 3 for _ in range(2)] for _ in range(n + 1)]
# Base case
for b in range(2):
for c in range(3):
dp[0][b][c] = 1
for length in range(1, n + 1):
for b in range(2):
for c in range(3):
# Place 'a'
dp[length][b][c] += dp[length - 1][b][c]
# Place 'b'
if b > 0:
dp[length][b][c] += dp[length - 1][b - 1][c]
# Place 'c'
if c > 0:
dp[length][b][c] += dp[length - 1][b][c - 1]
return dp[n][1][2]
# Driver code
if __name__ == "__main__":
n = 3
print(noOfString(n))
// C# program to count number of valid strings using iterative DP
using System;
class GfG {
static int noOfString(int n) {
int[,,] dp = new int[n + 1, 2, 3];
// Base case
for (int b = 0; b <= 1; b++) {
for (int c = 0; c <= 2; c++) {
dp[0, b, c] = 1;
}
}
for (int len = 1; len <= n; len++) {
for (int b = 0; b <= 1; b++) {
for (int c = 0; c <= 2; c++) {
// Place 'a'
dp[len, b, c] += dp[len - 1, b, c];
// Place 'b'
if (b > 0)
dp[len, b, c] += dp[len - 1, b - 1, c];
// Place 'c'
if (c > 0)
dp[len, b, c] += dp[len - 1, b, c - 1];
}
}
}
return dp[n, 1, 2];
}
static void Main(string[] args) {
int n = 3;
Console.WriteLine(noOfString(n));
}
}
// JavaScript program to count number of valid strings using iterative DP
function noOfString(n) {
// Initialize 3D array dp[len][b][c]
let dp = Array(n + 1);
for (let i = 0; i <= n; i++) {
dp[i] = Array(2);
for (let j = 0; j < 2; j++) {
dp[i][j] = Array(3).fill(0);
}
}
// Base case
for (let b = 0; b <= 1; b++) {
for (let c = 0; c <= 2; c++) {
dp[0][b][c] = 1;
}
}
for (let len = 1; len <= n; len++) {
for (let b = 0; b <= 1; b++) {
for (let c = 0; c <= 2; c++) {
// Place 'a'
dp[len][b][c] += dp[len - 1][b][c];
// Place 'b'
if (b > 0)
dp[len][b][c] += dp[len - 1][b - 1][c];
// Place 'c'
if (c > 0)
dp[len][b][c] += dp[len - 1][b][c - 1];
}
}
}
return dp[n][1][2];
}
// Driver code
const n = 3;
console.log(noOfString(n));
Output
19
[Optimal Mathematical Approach] Using Combinatorial Counting - O(1) Time and O(1) Space
The total number of valid strings is obtained by counting all possible arrangements for the following cases: one
'b', one'c', one'b'and one'c', two'c's, and one'b'with two'c's. Summing the counts of all these valid configurations simplifies to a closed-form formula.
- No 'b' or 'c' : only 1 way, all 'a's
- One 'b' : n ways
- One 'c': n ways
- Two 'c's : nC2 = n(n-1)/2
- One 'b' and one 'c' : n(n-1)
- One 'b' and two 'c's : n*[(n-1)C2] = n(n-1)(n-2)/2
Total ways = 1 + 2n + n(n-1)/2 + n(n-1) + n(n-1)(n-2)/2 = 1 + 2 * n + (3 * n * (n - 1)) / 2 + (n * (n - 1) * (n - 2)) / 2;
#include <bits/stdc++.h>
using namespace std;
int noOfString(int n)
{
return 1 + 2 * n + (3 * n * (n - 1)) / 2 + (n * (n - 1) * (n - 2)) / 2;
}
int main()
{
int n = 3;
cout << noOfString(n);
return 0;
}
// Java program to count number of valid strings using direct formula
import java.util.*;
class GfG {
static int noOfString(int n) {
return 1 + 2 * n + (3 * n * (n - 1)) / 2 + (n * (n - 1) * (n - 2)) / 2;
}
public static void main(String[] args) {
int n = 3;
System.out.println(noOfString(n));
}
}
# Python program to count number of valid strings using direct formula
def noOfString(n):
return 1 + 2 * n + (3 * n * (n - 1)) // 2 + (n * (n - 1) * (n - 2)) // 2
# Driver code
if __name__ == "__main__":
n = 3
print(noOfString(n))
// C# program to count number of valid strings using direct formula
using System;
class GfG {
static int noOfString(int n) {
return 1 + 2 * n + (3 * n * (n - 1)) / 2 + (n * (n - 1) * (n - 2)) / 2;
}
static void Main(string[] args) {
int n = 3;
Console.WriteLine(noOfString(n));
}
}
// JavaScript program to count number of valid strings using direct formula
function noOfString(n) {
return 1 + 2 * n + (3 * n * (n - 1)) / 2 + (n * (n - 1) * (n - 2)) / 2;
}
// Driver code
const n = 3;
console.log(noOfString(n));
Output
19