- 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
Number of substrings having an equal number of lowercase and uppercase letters
In this problem, we need to count the total number of strings of the given string containing an equal number of lowercase and uppercase characters. The naïve approach to solving the problem is to find all substrings and count the total number of substrings with an equal number of lowercase and uppercase characters.
The efficient approach is using the subarray sum problem. We can consider lowercase characters as -1 and uppercase characters as +1, and we will learn both approaches to solve the problem.
Problem statement- We have given string str containing the lowercase and uppercase alphabetical characters. We need to count the total number of substrings that contains an equal number of lowercase and uppercase characters.
Sample examples
Input – str = ‘TutOR’
Output – 4
Explanation–We can get ‘Tu’, ‘TutO’, ‘tO’, and ‘utOR’ total 4 substrings containing an equal number of lowercase and uppercase character
Input – str = ‘abcd’
Output – 0
Explanation– We can’t get any substring containing equal lowercase and uppercase characters as the string contains only lowercase characters
Input – str = ‘XYz’
Output – 1
Explanation– We can get only the ‘Yz’ substring.
Approach 1
This is the naïve approach to solving the problem. We will use 3 nested loops to find all substrings of the given string. We will check whether each substring contains an equal number of lowercase and uppercase characters. If yes, we increase the value of the count by 1.
Algorithm
Define the ‘cnt’ variable and initialize it with zero.
Use the for loop to iterate through the string
In the loop, define the ‘upperCase’ and ‘lowerCase’ variables and initialize them with zero
Add another nested loop to start iterating the string from the ith index. So, we can take a substring from the I to the jth index
In the nested loop, if the character is in uppercase, increase the value of the uppercase by 1. Otherwise, increase the value of a lowercase variable by 1.
If the value of the ‘upperCase’ and ‘lowerCase’ variables are equal, increase the ‘cnt’ value by 1.
Return the value of ‘cnt’.
Example
#include <iostream> using namespace std; // function to find the total number of substrings that have an equal number of lowercase and uppercase characters int totalSubStrings(string &str, int N){ // variable to store the count. int cnt = 0; for (int i = 0; i < str.length(); i++){ // variable to store the count of upper and lower case characters int upperCase = 0; int lowerCase = 0; for (int j = i; j < str.length(); j++){ // If the character is in uppercase, then increment upperCase if (str[j] >= 'A' && str[j] <= 'Z') upperCase++; else lowerCase++; // If the count of uppercase and lowercase characters is equal, then increment cnt if (upperCase == lowerCase) cnt++; } } return cnt; } int main(){ string str = "TutOR"; cout << "The total number of substrings that have equal lowercase and uppercase characters is " << totalSubStrings(str, str.length()); return 0; }
Output
The total number of substrings that have equal lowercase and uppercase characters is 4
Time complexity – O(N^2), as we use nested loops to find all substrings.
Space complexity – O(1), as we use constant space.
Approach 2
In this approach, we will optimize the code of the above approach to improve the time complexity of the solution. We will consider uppercase characters as +1 and lowercase characters as -1. Also, we will use the map data structure to store the frequency of the previous prefix sums. If we find a prefix sum equal to zero or the same as any prefix sum which is stored in the map, we can increase the count value.
Algorithm
Define the ‘sum’ map containing integers as a key-pairs value.
Define the ‘cnt’ variable and initialize with zero to store the total substring with equal lowercase and uppercase characters. Also, define the ‘current’ variable to store the prefix sum
Start traversing the string. Add 1 to the ‘current’ variable if the current character is in uppercase. Otherwise, subtract 1 from the ‘current’ character.
If the value of ‘current’ is 0, we found the substring and increased the value of ‘cnt’ by 1
Check if the map contains the ‘current’ as a key. If yes, get its value and add it to the ‘cnt’ variable.
Increase the value of the ‘current’ key by 1 in the map.
Example
For a better understanding of the problem. Let’s debug the example input, which is ‘TutOR’.
So, when we start iterating the string, the ‘current’ value will become 0 at the first index. So, increase the value of ‘cnt’ by 1. Again, it will be zero at the 3rd index. So, increase the ‘cnt’ value by 1, which will become 2. We also got 0 previously, so it exists in the map, and we need to add that value to the ‘cnt’. So, it will become 3.
When we reach the 4th index, the ‘current’ variable’s value will be 1, and we get it again, as we got it at the 0th index. So, add ‘1’ to the ‘cnt’.
The basic logic is that if ‘current’ is 0, we get the substring. If we got the ‘current’ value again, we could take the string between both indexes as ‘current – current’ is zero.
#include <iostream>
#include <unordered_map>
using namespace std;
// function to find the total number of substrings that have an equal number of lowercase and uppercase characters
int totalSubStrings(string &str, int N){
// map to store the frequency of sums generated by the difference in the count of lowercase and uppercase characters
unordered_map<int, int> sum;
// to store the count of substrings that have an equal number of lowercase and uppercase characters
int cnt = 0;
// current sum
int current = 0;
for (int i = 0; i < N; i++){
// If the character is uppercase, then increment the current value
if (str[i] >= 'A' and str[i] <= 'Z'){
current++;
}
// Otherwise, decrement the current value
else
current--;
// If the current value is 0, then a substring is found. So, increment the count by 1
if (current == 0)
cnt++;
// If the current value exists in the map, then update the cnt by adding the frequency of the current value
if (sum[current]){
cnt += (sum[current]);
}
// Increment the frequency of the current value in the map
sum[current]++;
}
return cnt;
}
int main(){
string str = "TutOR";
cout << "The total number of substrings that have equal lowercase and uppercase characters is " << totalSubStrings(str, str.length());
return 0;
}
Output
The total number of substrings that have equal lowercase and uppercase characters is 4
Time complexity – O(N), as we traverse the string once.
Space complexity – O(N), as we use the map to store prefix sum. In the worst-case scenario, when the string contains all lowercase or uppercase characters, we need O(N) space.
We learned to solve the above problem using two different approaches. The first approach checks all strings using nested loops, and the second approach is more efficient than the first in time complexity but more space-consuming.