- Trending Categories
Data Structure
Networking
RDBMS
Operating System
Java
MS Excel
iOS
HTML
CSS
Android
Python
C Programming
C++
C#
MongoDB
MySQL
Javascript
PHP
Physics
Chemistry
Biology
Mathematics
English
Economics
Psychology
Social Studies
Fashion Studies
Legal Studies
- Selected Reading
- UPSC IAS Exams Notes
- Developer's Best Practices
- Questions and Answers
- Effective Resume Writing
- HR Interview Questions
- Computer Glossary
- Who is Who
Count of Subsequences of given string X in between strings Y and Z
A subsequence is a string that can be achieved from another string by removing some (possibly none or all) from a given string that may not be continuous. We are given a string and have to find the number of subsequences that are greater than equal to the given string Y and less than equal to another given string Z. We will use dynamic programming to solve the problem as brute force will take exponential time.
Brute Force Approach
The brute forces approach is to find all the subsequences of the given string X and then check if they are lying in the given range. If the current subsequence is lying in the given range then we will increase the count.
Example
#include <bits/stdc++.h> using namespace std; // global varaibles string x, y, z; int len_x, len_y, len_z; // recursive function int rec(string& cur, int i){ // defining the base cases if(i == len_x){ if(cur <=z && cur >= y){ return 1; } else { return 0; } } int ans = rec(cur, i + 1); cur.push_back(x[i]); ans += rec(cur, i + 1); cur.pop_back(); return ans; } // function to get the number of subsequences less than Z and greater than Y int getCount(string X, string Y, string Z){ string cur = ""; // initializing empty string // getting the length of the given strings len_x = X.size(); len_y = Y.size(); len_z = Z.size(); // calling to the recursive function to get the result return rec(cur, 0); } int main(){ // given strings x = "abc"; y = "a"; z = "bc"; // edge case, if the given string y is greater than z // return zero if(y > z){ cout<<"The number of subsequences of given string X in between strings Y and Z are: "<<0<<endl; } else { // calling the function cout<<"The number of subsequences of given string X in between strings Y and Z are: "<<getCount(x,y,z) <<endl; } return 0; }
Output
The number of subsequences of given string X in between strings Y and Z are: 6
Time and Space Complexity
The time complexity of the above code is O((2^N) * N), where N is the size of the given string.
The space complexity of the above code is O(N), as we are using a string to store the current string.
Dynamic Programming Approach
We will make choice at each of the index, in first choice we will skip the current index value and move to the next value and for the second choice we will check if by adding the current character to the string is it in the range of not.
If by adding the current element in the string we will get result in the range then we will add to the answer. Also, if we already have visited this state then we will return already stored answer.
Example
#include <bits/stdc++.h> using namespace std; // array to store the state results int memo[105][105][2][2]; // global variables string x, y, z; int len_x, len_y, len_z; // recursive function int rec(int i, int j, bool var1, bool var2){ // defining the base cases if(i == len_x){ // if subsequence is empty then return 0 if (j == 0){ return 0; } if(var1 == false || j >= len_y){ return 1; } else { return 0; } } // if the memo array contains this item then return it if(memo[i][j][var1][var2] != -1){ return memo[i][j][var1][var2]; } // skip the current index int res = rec(i + 1, j, var1, var2); // variable to mark the position of current index int canAdded = 0; if(var1 == false) { canAdded = 1; } else if ((j >= len_y) || (x[i] >= y[j])) { canAdded = 1; var1 &= ((j < len_y) && x[i] == y[j]); } if (var2 == false){ canAdded ++; } else if((j < len_z) && x[i] <= z[j]){ canAdded++; var2 &= (x[i] == z[j]); } if (canAdded == 2){ // increase both i and j by 1 res += rec(i + 1, j + 1, var1, var2); } // store the answer in memo array memo[i][j][var1][var2] = res; return res; } // function to get the number of subsequences less than Z and greater than Y int getCount(string X, string Y, string Z){ // initialize the memo function memset(memo, -1, sizeof(memo)); // getting the lenght of the given strings len_x = X.size(); len_y = Y.size(); len_z = Z.size(); // calling to the recursive function to get the result return rec(0, 0, 1, 1); } int main(){ // given strings x = "abc"; y = "a"; z = "bc"; // edge case, if the given string y is greater than z // return zero if(y > z){ cout<<"The number of subsequences of given string X in between strings Y and Z are: "<<0<<endl; } else { // calling the function cout<<"The number of subsequences of given string X in between strings Y and Z are: "<<getCount(x,y,z) <<endl; } return 0; }
Output
The number of subsequences of given string X in between strings Y and Z are: 6
Time and Space Complexity
The time complexity of the above code is O(N*N), where N is the size of the given string.
The space complexity of the above code is O(N*N), as we are using an array to store the results or the states.
Conclusion
In this tutorial, we have implemented a program to find the number of subsequences of string X that are lying in between the given strings Y and Z. We have seen the simple brute force method which is in-efficient and then we have implemented the efficient dynamic programming code with the time complexity of O(N*N) and same space complexity.