Longest substring having K distinct vowels


In this article, we will explore the problem of finding the longest substring in a given string that contains K distinct vowels. The problem can be solved using different algorithms in C++. This problem is commonly encountered in the field of computer science, particularly in text processing and natural language processing tasks. It tests one's ability to manipulate strings and handle edge cases.

Syntax

In the realm of C++, the class std::string epitomizes a string datatype. This versatile entity enables storage and manipulation of character sequences.

The template class std::vector embodies a dynamic array, granting the ability to resize arrays and perform an array of operations on the encapsulated elements.

As a class template, std::unordered_map encapsulates an unordered map structure. It permits the stowage of singular key-value dyads, where keys remain unmatched and values can be retrieved employing these distinct keys.

The function template std::max yields the zenith of two values. This versatile mechanism facilitates comparisons between any datatype, as long as the > operator is duly defined.

std::string
std::vector
std::unordered_map
std::max

Algorithm

  • Start

  • Initialize variables to store the longest substring and its length.

  • Iterate through the string to find substrings with K distinct vowels.

  • Compare the lengths of the substrings and update the longest substring and its length accordingly.

  • Repeat steps 2 and 3 until all substrings are evaluated.

  • Return the longest substring.

  • End

Approaches

  • Approach 1 − Brute Force

  • Approach 2 − Sliding Window

Approach 1:- Brute Force

The implementation embodies a procedure of brute force to discover the most extensive substring of a string with precisely k unique vowels. The code initiates by defining two auxiliary functions: is_vowel and has_k_distinct_vowels.

Example

The is_vowel function receives a solitary character as input and yields a truth if the character is a vowel (e.g. 'a', 'e', 'i', 'o', or 'u') and a falsehood otherwise. This function is later applied to affirm if a character is a vowel.

The has_k_distinct_vowels function takes in a string and an integer k as input and returns a truth if the string accommodates exactly k unique vowels and a falsehood otherwise. This function employs an unordered_set to keep a record of the vowels in the string and to count the number of unique vowels in the string.

The primary function longest_substring_bruteforce receives a string and an integer k as input and returns the longest substring of the string that comprises precisely k unique vowels.

This is accomplished by utilizing two nested for loops to traverse all the possible substrings of the string. For every substring, it invokes the has_k_distinct_vowels function to validate if the substring has exactly k unique vowels.

If the present substring has k unique vowels and is more extensive than the current longest substring, the present substring transforms into the new longest substring.

Finally, the code inputs a string and an integer k, calls the longest_substring_bruteforce function to find the longest substring with k unique vowels, and outputs the result.

#include <iostream>
#include <string>
#include <unordered_set>

bool is_vowel(char c) {
   return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}

bool has_k_distinct_vowels(const std::string &s, int k) {
   std::unordered_set<char> vowel_set;
   for (char c : s) {
      if (is_vowel(c)) {
         vowel_set.insert(c);
      }
   }
   return vowel_set.size() == k;
}

std::string longest_substring_bruteforce(const std::string &s, int k) {
   std::string longest_substring = "";
   int max_len = 0;

   for (int i = 0; i < s.size(); ++i) {
      for (int j = i; j < s.size(); ++j) {
         std::string current_substring = s.substr(i, j - i + 1);
         if (has_k_distinct_vowels(current_substring, k) && current_substring.size() > max_len) {
         longest_substring = current_substring;
         max_len = current_substring.size();
         }
      }
   }

   return longest_substring;
}

int main() {
   std::string input = "aeiaaioooaauuaeiu";
   int k = 3;
   std::string result = longest_substring_bruteforce(input, k);
   std::cout << "Longest substring with " << k << " distinct vowels: " << result << std::endl;
   return 0;
}

Output

Longest substring with 3 distinct vowels: iaaioooaa

Approach 2:- Sliding Window

The sliding window approach is a technique used to solve problems in computer science and algorithms. It is used to find a specific pattern in a given input, such as a substring or subarray, that meets certain criteria.

In this approach, two pointers are used to create a window that slides through the input. The size of the window is adjusted as needed to ensure that it meets the desired criteria. The algorithm keeps track of the properties of the current window, such as the number of distinct elements, sum of elements, etc.

Example

The is_vowel function is a helper function that returns true if the given character is a vowel (i.e., a, e, i, o, or u).

The main function, longest_substring_slidingwindow, takes a string s and an integer k as inputs. It uses two pointers, left and right, to create a sliding window and iterate through the string.

An unordered map freq is used to keep track of the frequency of each vowel in the current window. When the frequency of vowels in the window exceeds k, the left pointer is moved to the right until the frequency of vowels is equal to k again. The length of the current window is calculated as right - left + 1, and if it is greater than the maximum length seen so far, the start index and length are updated.

Finally, the function returns the longest substring with k distinct vowels using the substr method of the string class.

#include <iostream>
#include <string>
#include <unordered_map>

bool is_vowel(char c) {
   return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}

std::string longest_substring_slidingwindow(const std::string &s, int k) {
   int left = 0, right = 0, max_len = 0, start = 0;
   std::unordered_map<char, int> freq;

   while (right < s.size()) {
      char c = s[right];
      if (is_vowel(c)) {
         freq[c]++;
      }

      while (freq.size() > k) {
         char left_char = s[left];
         if (is_vowel(left_char)) {
            freq[left_char]--;
            if (freq[left_char] == 0) {
               freq.erase(left_char);
            }
         }
         left++;
      }

      if (freq.size() == k && (right - left + 1) > max_len) {
         max_len = right - left + 1;
         start = left;
      }

      right++;
   }

   return s.substr(start, max_len);
}

int main() {
   std::string input = "aeiaaioooaauuaeiu";
   int k = 3;
   std::string result = longest_substring_slidingwindow(input, k);
   std::cout << "Longest substring with " << k << " distinct vowels: " << result << std::endl;
   return 0;
}

Output

Longest substring with 3 distinct vowels: iaaioooaa

Conclusion

In this article, we have discussed two approaches to solve the problem of finding the longest substring in a given string that contains K distinct vowels. The first approach is the Brute Force method, while the second approach is the Sliding Window method. The Brute Force approach has a time complexity of O(n^3) making it a more efficient solution for larger inputs. The Sliding Window approach is recommended for solving this problem due to its lower time complexity.

Updated on: 21-Jul-2023

124 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements