Given an integer N and string S of size M, the task is to find the number of ways of forming string of length N such that it is possible to rearrange the string to have S as substring. Print the answer modulo 109 + 7.
Note: All characters of string S are distinct.
Examples:
Input: N = 3, S = “abc”
Output: 6
Explanation: There are 6 strings that can be rearranged to have string S as substring: Those strings are “abc”, “acb”, “bac”, “bca”, “cab” and “cba”.Input: N = 4, S = “abc”
Output: 588
Explanation: Some possible strings from 588 strings are “bcaz”, “zabc”, “abcc” and “abbc” whose characters can be rearranged to have “abc” as substring.
Approach: Implement the idea below to solve the problem
Bitmask Dynamic Programming can be used to solve this problem. We can maintain dp[i][j] stores the number of ways to have string S as the substring if we are at index i with submask j. The submask stores which characters we have already taken into our string. If submask j has 0th bit as set then it means that character at index 0 of string S is already present in our string. At any index i, we have 2 choices:
- Choice 1: Choose any character from string S to be placed at index i.
- Choice 2: Choose any character which is not present in string S to be placed at index i.
Explore all the choices to get the final answer.
Steps to solve the problem:
- Define a recursive function, say countOfArr(idx, bitmask) which returns the number of ways to have string S as a substring if we are at index idx and have selected characters represented by bitmask.
- If we have iterated through the whole string, the check if our string has all the characters which are present in S by comparing the submask. If yes, return 1 else return 0.
- If we are at any other index, iterate over all the characters of string S and place every character at index idx.
- Also place all those characters which are not present in string S at index idx.
- Count all the choices to get the final answer.
Code to implement the approach:
#include <bits/stdc++.h> using namespace std;
const int MOD = 1e9 + 7;
// to avoid interger overflow #define int long long // Function to find ways to form N sized string which has // string S as substring after rearranging formed string int countOfArr( int idx, int bitmask, string& S, int N,
int M, vector<vector< int > >& dp)
{ // base case
if (idx == N) {
return bitmask == ((1 << M) - 1);
}
if (dp[idx][bitmask] != -1)
return dp[idx][bitmask];
int ans = 0;
// Choose any one character of string S to be placed at
// index i
for ( int i = 0; i < M; i++) {
ans += countOfArr(idx + 1, bitmask | (1LL << i), S,
N, M, dp);
ans %= MOD;
}
// Choose a character which is not present in string S
// to be placed at index i
ans += ((26 - M)
* countOfArr(idx + 1, bitmask, S, N, M, dp))
% MOD;
// returning final answer
return dp[idx][bitmask] = ans;
} // Driver Code int32_t main() { // Input
int N = 4, M = 3;
string S = "abc" ;
// DP array initalized with -1
vector<vector< int > > dp(N + 1,
vector< int >((1 << M), -1));
int bitmask = 0;
// Function Call
cout << countOfArr(0, bitmask, S, N, M, dp) << endl;
return 0;
} |
import java.util.Arrays;
class GFG
{ static final int MOD = 1000000007 ;
// Function to find ways to form N sized
// string which has string S as substring
// after rearranging formed string
static int countOfArr( int idx, int bitmask,
String S, int N, int M,
int [][] dp)
{
// base case
if (idx == N) {
return bitmask == (( 1 << M) - 1 ) ? 1 : 0 ;
}
if (dp[idx][bitmask] != - 1 )
return dp[idx][bitmask];
int ans = 0 ;
// Choose any one character of string S
// to be placed at index i
for ( int i = 0 ; i < M; i++) {
ans += countOfArr(idx + 1 , bitmask | ( 1 << i),
S, N, M, dp);
ans %= MOD;
}
// Choose a character which is not present
// in string S to be placed at index i
ans += (( 26 - M) * countOfArr(idx + 1 , bitmask, S, N, M, dp)) % MOD;
// returning final answer
return dp[idx][bitmask] = ans;
}
// Driver Code
public static void main(String[] args)
{
// Input
int N = 4 , M = 3 ;
String S = "abc" ;
// DP array initalized with -1
int [][] dp = new int [N + 1 ][( 1 << M)];
for ( int [] row : dp) {
Arrays.fill(row, - 1 );
}
int bitmask = 0 ;
// Function Call
System.out.println(countOfArr( 0 , bitmask, S, N, M, dp));
}
} |
MOD = 10 * * 9 + 7
# Function to find ways to form N sized string which has # string S as substring after rearranging formed string def countOfArr(idx, bitmask, S, N, M, dp):
# Base case
if idx = = N:
return bitmask = = (( 1 << M) - 1 )
if dp[idx][bitmask] ! = - 1 :
return dp[idx][bitmask]
ans = 0
# Choose any one character of string S to be placed at
# index i
for i in range (M):
ans + = countOfArr(idx + 1 , bitmask | ( 1 << i), S, N, M, dp)
ans % = MOD
# Choose a character which is not present in string S
# to be placed at index i
ans + = (( 26 - M) * countOfArr(idx + 1 , bitmask, S, N, M, dp)) % MOD
# returning final answer
dp[idx][bitmask] = ans
return ans
# Driver Code if __name__ = = "__main__" :
# Input
N = 4
M = 3
S = "abc"
# DP array initialized with -1
dp = [[ - 1 for _ in range ( 1 << M)] for _ in range (N + 1 )]
bitmask = 0
# Function Call
print (countOfArr( 0 , bitmask, S, N, M, dp))
|
using System;
using System.Collections.Generic;
class Program
{ const int MOD = 1000000007;
static long CountOfArr( int idx, int bitmask, string S, int N, int M, long [,] dp)
{
// base case
if (idx == N)
{
return bitmask == ((1 << M) - 1) ? 1 : 0;
}
if (dp[idx, bitmask] != -1)
return dp[idx, bitmask];
long ans = 0;
// Choose any one character of string S to be placed at index i
for ( int i = 0; i < M; i++)
{
ans += CountOfArr(idx + 1, bitmask | (1 << i), S, N, M, dp);
ans %= MOD;
}
// Choose a character which is not present in string S to be placed at index i
ans += ((26 - M) * CountOfArr(idx + 1, bitmask, S, N, M, dp)) % MOD;
// returning final answer
return dp[idx, bitmask] = ans;
}
static void Main()
{
// Input
int N = 4, M = 3;
string S = "abc" ;
// DP array initialized with -1
long [,] dp = new long [N + 1, 1 << M];
for ( int i = 0; i <= N; i++)
{
for ( int j = 0; j < 1 << M; j++)
{
dp[i, j] = -1;
}
}
int bitmask = 0;
// Function Call
Console.WriteLine(CountOfArr(0, bitmask, S, N, M, dp));
}
} |
const MOD = 1e9 + 7; function GFG(idx, bitmask, S, N, M, dp) {
// base case
if (idx === N) {
return bitmask === (1 << M) - 1 ? 1 : 0;
}
if (dp[idx][bitmask] !== -1) {
return dp[idx][bitmask];
}
let ans = 0;
// Choose any one character of the string S to be placed at index i
for (let i = 0; i < M; i++) {
ans += GFG(idx + 1, bitmask | (1 << i), S, N, M, dp);
ans %= MOD;
}
// Choose a character which is not present in string S to be placed at index i
ans += ((26 - M) * GFG(idx + 1, bitmask, S, N, M, dp)) % MOD;
// returning final answer
dp[idx][bitmask] = ans;
return ans;
} // Driver Code function main() {
// Input
let N = 4;
let M = 3;
let S = "abc" ;
let dp = new Array(N + 1).fill(0).map(() => new Array(1 << M).fill(-1));
let bitmask = 0;
// Function Call
console.log(GFG(0, bitmask, S, N, M, dp));
} main(); |
588
Time Complexity: O( N * 2M), where N is the length of string we have to make and M is the length of input string S.
Auxiliary Space: O(N * 2M)