Count of substrings with the frequency of at most one character as Odd


Substrings are the subsets or sequences of contiguous characters of a string.

Now, in this problem, we need to find the number of substrings with the frequency of at most one character as odd. Let us see how we should proceed to solve this problem.

Let’s try to understand this problem with the help of some examples.

Input

s = “ksjssjkk”

Output

21

Explanation − As the frequency of the characters in the given string is given below−

  • k → 3

  • s → 3

  • j → 2

Now, substrings with at most one character occurring at an odd number of time times can be−

  • Take each character: ‘k’, ‘s’, ‘j’, ‘s’, ‘s’, ‘j’, ‘k’, ‘k’ = 8

  • Take 2 letters at a time: ‘ss’, ‘kk’ = 2

  • Take 3 letters at a time: ‘sjs’, ‘jss’, ‘ssj’, ‘jkk’ = 4

  • Take 4 letters at a time: ‘jssj’ = 1

  • Take 5 letters at a time: ‘sjssj’, ‘jssjk’, ‘ssjkk’ = 3

  • Take 6 letters at a time: ‘jssjkk’ = 1

  • Take 7 letters at a time: ‘ksjssjk’, ‘sjssjkk’ = 2

  • Take 8 letters at a time: No string

Now, adding the number of substrings we get (8 + 2 + 4 + 1 + 3 + 1 + 2) = 21

Input

s = “ab”

Output

2

Explanation − 2 substrings we will get are: ‘a’, ‘b’

Problem Explanation

Let’s try to understand the problem and find its solution. We have to find those substrings in the string where at most, one letter appears an odd number of times, i.e., in whole, there is at most one letter whose frequency is odd.

Solution-1: Brute Force Solution

Approach

This is an easy-to-understand approach. We will simply run loops to get access to all substrings and we will keep on checking if there is only one letter with odd frequency or not. If yes, we will include the substring in our final output.

Example

The following are implementations of the above approach in various programming languages −

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool checkValid(const char* s){
   int n = strlen(s);
   // Define Frequency vector
   int Freq[26] = {0};
   // Define a variable named oddFreq to calculate total odd frequencies
   int oddFreq = 0;
   // Run a loop to count the frequencies of each character
   for (int i = 0; i < n; i++) {
      if (s[i] >= 'a' && s[i] <= 'z') {
         Freq[s[i] - 'a']++;
      }
   }
   // Run a loop to calculate the number of frequencies that are odd
   for (int i = 0; i < 26; i++) {
      if (Freq[i] % 2 != 0)
         oddFreq++;
   }
   // Check if the frequency of any character is odd in number more than one then return false, else return true
   if (oddFreq <= 1) return true;
   else return false;
}

// Function to count the number of substrings with the frequency of at most one character as Odd
int Helper(const char* s){
   // Define the size of the string
   int n = strlen(s);
   // Define a variable output initiated by zero
   int output = 0;
   // Run a loop to traverse through the string
   for(int i = 0; i < n; i++) {
      // Run another loop inside the first loop to get substrings
      for (int j = i; j < n; j++) {
         // Get substring from i to j
         char S[100]; // Use an array to store the substring
         strncpy(S, s + i, j - i + 1);
         S[j - i + 1] = '\0'; // Null-terminate the substring
         if (checkValid(S)) output++;
      }
   }
   // Return the final output
   return output;
}
int main(){
   const char* s = "ksjssjkk";
   // Call the helper function to get the final output
   int output = Helper(s);
   // Print the output
   printf("The number of substrings with the frequency of at most one character as Odd is: %d", output);
   return 0;
}

Output

The number of substrings with the frequency of at most one character as Odd is: 21
#include <bits/stdc++.h>
using namespace std;
// Function which will check the string is valid
bool checkValid(string s){
   int n = s.size();
   // Define Frequency vector
   int Freq[26] = {0};
   // Define a variable named oddFreq to calculate total odd frequencies
   int oddFreq = 0;
   // Run a loop to count the frequencies of each character
   for (int i = 0; i < n; i++) {
      Freq[s[i] - 'a']++;
   }
   // Run a loop to calculate the number of frequencies that are odd
   for (int i = 0; i < 26; i++) {
      if (Freq[i] % 2 != 0)
         oddFreq++;
   }
   // Check if the frequency of any character is odd in number more than one then return false, else return true
   if (oddFreq <= 1) return true;
   else return false;
}
// Function to count the number of substrings with the frequency of at most one character as Odd
int Helper(string s){
   // Define the size of the string
   int n = s.size();
   // Define a variable output initiated by zero
   int output = 0;
   // Run a loop to traverse through the string
   for(int i = 0; i < n; i++) {
      // Run another loop inside the first loop to get substrings
      for (int j = i; j < n; j++) {
         // Get substring from i to j
         string S = s.substr(i, j - i + 1);
         if (checkValid(S)) output++;
      }
   }
   // Return the final output
   return output;
}
int main(){
   // Give input string by the user
   string s = "ksjssjkk" ;
   // Call the helper function to get the final output
   int output = Helper(s);
   // Print the output
   cout << "The number of substrings with the frequency of at most one character as Odd is: " << output;
   return 0;
}

Output

The number of substrings with the frequency of at most one character as Odd is: 21
public class Main {
   public static boolean checkValid(String s) {
      int n = s.length();
      // Define Frequency vector
      int[] Freq = new int[26];
      // Define a variable named oddFreq to calculate total odd frequencies
      int oddFreq = 0;
      // Run a loop to count the frequencies of each character
      for (int i = 0; i < n; i++) {
         Freq[s.charAt(i) - 'a']++;
      }
      // Run a loop to calculate the number of frequencies that are odd
      for (int i = 0; i < 26; i++) {
         if (Freq[i] % 2 != 0)
            oddFreq++;
      }
      // Check if the frequency of any character is odd in number more than one then return false, else return true
      return oddFreq <= 1;
   }

   // Function to count the number of substrings with the frequency of at most one character as Odd
   public static int Helper(String s) {
      // Define the size of the string
      int n = s.length();
      // Define a variable output initiated by zero
      int output = 0;
      // Run a loop to traverse through the string
      for (int i = 0; i < n; i++) {
         // Run another loop inside the first loop to get substrings
         for (int j = i; j < n; j++) {
            // Get substring from i to j
            String S = s.substring(i, j + 1); // Corrected to use substring
            if (checkValid(S)) output++;
         }
      }
      return output;
   }
   public static void main(String[] args) {
      // Give input string by the user
      String s = "ksjssjkk";
      // Call the helper function to get the final output
      int output = Helper(s);
      // Print the output
      System.out.println("The number of substrings with the frequency of at most one character as Odd is: " + output);
   }
}

Output

The number of substrings with the frequency of at most one character as Odd is: 21
# Function to check if the string is valid
def checkValid(s):
   n = len(s)
   # Define a frequency vector
   Freq = [0] * 26
   # Define a variable named oddFreq to calculate total odd frequencies
   oddFreq = 0
   # Run a loop to count the frequencies of each character
   for i in range(n):
      Freq[ord(s[i]) - ord('a')] += 1
   # Run a loop to calculate the number of frequencies that are odd
   for i in range(26):
      if Freq[i] % 2 != 0:
         oddFreq += 1
   # Check if the frequency of any character is odd in number more than one then return False, else return True
   return oddFreq <= 1

# Function to count the number of substrings with the frequency of at most one character as Odd
def Helper(s):
   n = len(s)
   # Define a variable output initiated by zero
   output = 0
   # Run a loop to traverse through the string
   for i in range(n):
      # Run another loop inside the first loop to get substrings
      for j in range(i, n):
         # Get substring from i to j
         S = s[i:j+1]
         if checkValid(S):
            output += 1
   # Return the final output
   return output

def main():
   # Give input string
   s = "ksjssjkk"
   # Call the Helper function to get the final output
   output = Helper(s)
   # Print the output
   print("The number of substrings with the frequency of at most one character as Odd is:", output)

if __name__ == "__main__":
   main()

Output

The number of substrings with the frequency of at most one character as Odd is: 21

Complexities for the above code

  • Time complexity − O(n^3); where n is the size of the string, here (n^3) is the time complexity of the helper function while the checkValid function itself takes (O(n)) time to execute.

  • Space complexity − O(1); We have not stored any variable in some data structure in the above code.

Solution-2: Optimized Solution using Bit-masking

Bit-masking

Bitmasking is the act of applying a mask over a value to keep, change or modify a piece of given information. A mask determines which bits to take and which bits to clear off a binary number. It can be used to mask a value to represent the subsets of a set using various bitwise operations.

Approach

We use a bitmask to indicate what characters are used the odd number of times, and we use a hashmap to keep track of previously seen bitmasks. We will increase the hashmap[bitmask] by one after each iteration, indicating that we are acquainted with this bitmask. The substrings with an even number of letters utilized will be counted when output += m[mask]. while output+= m[mask^ (1<<j)] will count the substrings when precisely one letter appears odd times.

Example

The following are implementations of the above approach in various programming languages −

#include <bits/stdc++.h>
using namespace std;
int Helper(string s){
   // Declare an Unordered map which would tell us if the frequency of bitmasks is odd or even that is 0 if that character has occurred even times and 1 if it has occurred odd times
   unordered_map<int, int> m;
   // Initiate the frequency bitmask
   m[0] = 1;
   // Store the current bitmask
   int mask = 0;
   // Initialize the output as 0
   int output = 0;
   // Run a loop to start masking
   for (int i = 0; i < s.size(); ++i) {
      // masking the current character
      mask ^= (1 << (s[i] - 'a'));
      // Count the substrings that have all alphabets used even the number of times
      output += m[mask];
      for (int j = 0; j < 26; ++j) {
         // Count the substrings that have exactly 1 used character
         output += m[mask ^ (1 << j)];
      }
      m[mask]++;
   }
   // Return the final output
   return output;
}
int main(){
   // Give input string by the user
   string s = "ksjssjkk" ;
   // Call the helper function to get the final output
   int output = Helper(s);
   // Print the output
   cout << "The number of substrings with the frequency of at most one character as Odd is: " << output;
   return 0;
}

Output

The number of substrings with the frequency of at most one character as Odd is: 21
import java.util.HashMap;
public class Main {
   public static int Helper(String s) {
      HashMap<Integer, Integer> m = new HashMap<>();
      // Initiate the frequency bitmask
      m.put(0, 1);
      // Store the current bitmask
      int mask = 0;
      int output = 0;

      // Run a loop to start masking
      for (int i = 0; i < s.length(); i++) {
         // masking the current character
         mask ^= (1 << (s.charAt(i) - 'a'));
         // Count the substrings that have all alphabets used even the number of times
         output += m.getOrDefault(mask, 0);

         for (int j = 0; j < 26; j++) {
            // Count the substrings that have exactly 1 used character
            output += m.getOrDefault(mask ^ (1 << j), 0);
         }
         m.put(mask, m.getOrDefault(mask, 0) + 1);
      }
      // Return the final output
      return output;
   }

   public static void main(String[] args) {
      // Give input string by the user
      String s = "ksjssjkk";
      // Call the helper function to get the final output
      int output = Helper(s);
      System.out.println("The number of substrings with the frequency of at most one character as Odd is: " + output);
   }
}

Output

The number of substrings with the frequency of at most one character as Odd is: 21
def Helper(s):
   # Initiate the frequency bitmask
   m = {0: 1}
   # Store the current bitmask
   mask = 0
   output = 0

   # Run a loop to start masking
   for i in range(len(s)):
      # masking the current character
      mask ^= (1 << (ord(s[i]) - ord('a')))
      # Count the substrings that have all alphabets used even the number of times
      output += m.get(mask, 0)

      for j in range(26):
         # Count the substrings that have exactly 1 used character
         output += m.get(mask ^ (1 << j), 0)
      m[mask] = m.get(mask, 0) + 1

   # Return the final output
   return output

def main():
   # Give input string by the user
   s = "ksjssjkk"
   # Call the helper function to get the final output
   output = Helper(s)
   print("The number of substrings with the frequency of at most one character as Odd is:",output)

if __name__ == "__main__":
   main()

Output

The number of substrings with the frequency of at most one character as Odd is: 21

Complexities for the Above Code

  • Time complexity − O(n*26); where n is the size of the string. As for each character of the string, we have a check for 26 total characters.

  • Space complexity − O(1); We used a map data structure only which would occupy O(26) space which is relatively equal to O(1) space complexity.

Conclusion

In this article, to find the number of substrings with the frequency of at most one character as odd. Firstly, we will apply the naive approach to get the output using loops, it is an easy-to-understand approach but the only drawback of that approach is that it will be executed with a huge time complexity. However, we can easily deduce the time complexity of the code by using another technique called bitmasking using hashmaps. This question, in particular, is a peculiar example of the application of bitmasking technique as it deduced time complexity from O(n^3) to O(n). In this article, we learned the use and concepts of bitmasking.

Updated on: 05-Feb-2024

134 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements