Count number of substrings with exactly k distinct characters
Given a string of lowercase alphabets, count all possible substrings (not necessarily distinct) that has exactly k distinct characters.
Examples:
Input: abc, k = 2
Output: 2
Possible substrings are {“ab”, “bc”}Input: aba, k = 2
Output: 3
Possible substrings are {“ab”, “ba”, “aba”}Input: aa, k = 1
Output: 3
Possible substrings are {“a”, “a”, “aa”}
Method 1 (Brute Force): If the length of string is n, then there can be n*(n+1)/2 possible substrings. A simple way is to generate all the substring and check each one whether it has exactly k unique characters or not. If we apply this brute force, it would take O(n*n) to generate all substrings and O(n) to do a check on each one. Thus overall it would go O(n*n*n)
Method 2: The problem can be solved in O(n*n). Idea is to maintain a hash table while generating substring and checking the number of unique characters using that hash table.
The implementation below assume that the input string contains only characters from ‘a’ to ‘z’.
Implementation
// C++ program to count number of substrings with
// exactly k distinct characters in a given string
#include<bits/stdc++.h>
using namespace std;
// Function to count number of substrings
// with exactly k unique characters
int countkDist(string str, int k)
{
int n = str.length();
// Initialize result
int res = 0;
// To store count of characters from 'a' to 'z'
int cnt[26];
// Consider all substrings beginning with
// str[i]
for (int i = 0; i < n; i++)
{
int dist_count = 0;
// Initializing array with 0
memset(cnt, 0, sizeof(cnt));
// Consider all substrings between str[i..j]
for (int j=i; j<n; j++)
{
// If this is a new character for this
// substring, increment dist_count.
if (cnt[str[j] - 'a'] == 0)
dist_count++;
// Increment count of current character
cnt[str[j] - 'a']++;
// If distinct character count becomes k,
// then increment result.
if (dist_count == k)
res++;
if(dist_count > k) break;
}
}
return res;
}
// Driver Program
int main()
{
string str = "abcbaa";
int k = 3;
cout << "Total substrings with exactly "
<< k <<" distinct characters :"
<< countkDist(str, k) << endl;
return 0;
}
// Java program to CountKSubStr number of substrings
// with exactly distinct characters in a given string
import java.util.Arrays;
public class CountKSubStr
{
// Function to count number of substrings
// with exactly k unique characters
int countkDist(String str, int k)
{
// Initialize result
int res = 0;
int n = str.length();
// To store seen characters from 'a' to 'z'
boolean seen[] = new boolean[26];
// Consider all substrings beginning with
// str[i]
for (int i = 0; i < n; i++)
{
int distCount = 0;
// mark all chars as unseen
Arrays.fill(seen, false);
// Consider all substrings between str[i..j]
for (int j=i; j<n; j++)
{
// If this is a new character for this
// substring, increment dist_count.
if (!seen[str.charAt(j) - 'a'])
distCount++;
// mark current char as seen
seen[str.charAt(j) - 'a'] = true;
// If distinct character count becomes k,
// then increment result.
if (distCount == k)
res++;
}
}
return res;
}
// Driver Program
public static void main(String[] args)
{
CountKSubStr ob = new CountKSubStr();
String ch = "abcbaa";
int k = 3;
System.out.println("Total substrings with exactly " +
k + " distinct characters : "
+ ob.countkDist(ch, k));
}
}
def countkDist(s, k):
n = len(s)
res = 0
# Consider all substrings beginning with str[i]
for i in range(n):
dist_count = 0
cnt = [0] * 26 # To store count of characters from 'a' to 'z'
# Consider all substrings between str[i..j]
for j in range(i, n):
# If this is a new character for this substring, increment dist_count.
if cnt[ord(s[j]) - ord('a')] == 0:
dist_count += 1
# Increment count of current character
cnt[ord(s[j]) - ord('a')] += 1
# If distinct character count becomes k, then increment result.
if dist_count == k:
res += 1
if dist_count > k:
break
return res
# Driver Program
if __name__ == "__main__":
s = "abcbaa"
k = 3
print("Total substrings with exactly", k,
"distinct characters:", countkDist(s, k))
// C# program to CountKSubStr number of substrings
// with exactly distinct characters in a given string
using System;
public class CountKSubStr
{
// Function to count number of substrings
// with exactly k unique characters
int countkDist(string str, int k)
{
// Initialize result
int res = 0;
int n = str.Length;
// To store count of characters from 'a' to 'z'
int[] cnt = new int[26];
// Consider all substrings beginning with
// str[i]
for (int i = 0; i < n; i++)
{
int dist_count = 0;
// Initializing count array with 0
Array.Clear(cnt, 0,cnt.Length);
// Consider all substrings between str[i..j]
for (int j=i; j<n; j++)
{
// If this is a new character for this
// substring, increment dist_count.
if (cnt[str[j] - 'a'] == 0)
dist_count++;
// Increment count of current character
cnt[str[j] - 'a']++;
// If distinct character count becomes k,
// then increment result.
if (dist_count == k)
res++;
}
}
return res;
}
// Driver Program
public static void Main()
{
CountKSubStr ob = new CountKSubStr();
string ch = "abcbaa";
int k = 3;
Console.Write("Total substrings with exactly " +
k + " distinct characters : "
+ ob.countkDist(ch, k));
}
}
<script>
// javascript program to CountKSubStr number of substrings
// with exactly distinct characters in a given string
// Function to count number of substrings
// with exactly k unique characters
function countkDist(str , k)
{
// Initialize result
var res = 0;
var n = str.length;
// To store count of characters from 'a' to 'z'
var cnt = Array.from({length: 26}, (_, i) => 0);
// Consider all substrings beginning with
// str[i]
for (i = 0; i < n; i++)
{
var dist_count = 0;
// Consider all substrings between str[i..j]
for (j=i; j<n; j++)
{
// If this is a new character for this
// substring, increment dist_count.
if (cnt[str.charAt(j).charCodeAt(0) - 'a'.charCodeAt(0)] == 0)
dist_count++;
// Increment count of current character
cnt[str.charAt(j).charCodeAt(0) - 'a'.charCodeAt(0)]++;
// If distinct character count becomes k,
// then increment result.
if (dist_count == k)
res++;
}
}
return res;
}
// Driver Program
var ch = "abcbaa";
var k = 3;
document.write("Total substrings with exactly " +
k + " distinct characters : "
+ countkDist(ch, k));
// This code contributed by shikhasingrajput
</script>
<?php
// PHP program to CountKSubStr number of substrings
// with exactly distinct characters in a given string
// Function to count number of substrings
// with exactly k unique characters
function countkDist($str, $k)
{
// Initialize result
$res = 0;
$n = strlen($str);
// To store count of characters from 'a' to 'z'
$cnt = array();
// Consider all substrings beginning with
// str[i]
for ($i = 0; $i < $n; $i++)
{
$dist_count = 0;
// Initializing count array with 0
$cnt = array_fill(0, 0, true);
// Consider all substrings between str[i..j]
for ($j = $i; $j < $n; $j++)
{
// If this is a new character for this
// substring, increment dist_count.
if ($cnt[ord($str[$j]) - ord('a')] == 0)
$dist_count++;
// Increment count of current character
$cnt[ord($str[$j]) - ord('a')]++;
// If distinct character count becomes k,
// then increment result.
if ($dist_count == $k)
$res++;
}
}
return $res;
}
// Driver code
{
$ch = "abcbaa";
$k = 3;
echo("Total substrings with exactly " .
$k . " distinct characters : "
. countkDist($ch, $k));
}
// This code is contributed by Code_Mech
Output
Total substrings with exactly 3 distinct characters :8
Time Complexity: O(n*n)
Auxiliary Space: O(1), Only 26 size array is used, which can be considered constant space.
Efficient Approach: The idea is to count all the subarrays with at most K distinct characters and then subtract all the subarrays with atmost K – 1 characters. That leaves us with count of subarrays with exactly K distinct characters.
Below is the implementation of the above approach:
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
// the number of subarrays with at most K distinct elements
int most_k_chars(string& s, int k)
{
if (s.size() == 0) {
return 0;
}
unordered_map<char, int> map;
int num = 0, left = 0;
for (int i = 0; i < s.size(); i++) {
map[s[i]]++;
while (map.size() > k) {
map[s[left]]--;
if (map[s[left]] == 0) {
map.erase(s[left]);
}
left++;
}
num += i - left + 1;
}
return num;
}
int exact_k_chars(string& s, int k)
{
return most_k_chars(s, k) - most_k_chars(s, k - 1);
}
// Driver Program
int main()
{
string s1 = "pqpqs";
int k = 2;
cout << "Total substrings with exactly " << k
<< " distinct characters : "
<< exact_k_chars(s1, k) << endl;
string s2 = "aabab";
k = 2;
cout << "Total substrings with exactly " << k
<< " distinct characters : "
<< exact_k_chars(s2, k) << endl;
}
import java.io.*;
import java.util.HashMap;
public class GFG
{
// the number of subarrays with at most K distinct
// elements
static int most_k_chars(String s, int k)
{
if (s.length() == 0) {
return 0;
}
HashMap<Character, Integer> map = new HashMap<>();
int num = 0, left = 0;
for (int i = 0; i < s.length(); i++) {
map.put(s.charAt(i),
map.getOrDefault(s.charAt(i), 0) + 1);
while (map.size() > k) {
map.put(s.charAt(left),
map.getOrDefault(s.charAt(left), 0)
- 1);
if (map.get(s.charAt(left)) == 0) {
map.remove(s.charAt(left));
}
left++;
}
num += i - left + 1;
}
return num;
}
static int exact_k_chars(String s, int k)
{
return most_k_chars(s, k) - most_k_chars(s, k - 1);
}
public static void main(String[] args)
{
String s1 = "pqpqs";
int k = 2;
System.out.println("Total substrings with exactly "
+ k + " distinct characters : "
+ exact_k_chars(s1, k));
String s2 = "aabab";
k = 2;
System.out.println("Total substrings with exactly "
+ k + " distinct characters : "
+ exact_k_chars(s2, k));
}
}
// This code is contributed by garg28harsh.
# Python code
# the number of subarrays with at most K distinct elements
def most_k_chars(s, k):
if not s:
return 0
char_count = {}
num = 0
left = 0
for i in range(len(s)):
char_count[s[i]] = char_count.get(s[i], 0) + 1
while len(char_count) > k:
char_count[s[left]] -= 1
if char_count[s[left]] == 0:
char_count.pop(s[left])
left += 1
num += i - left + 1
return num
def exact_k_chars(s, k):
return most_k_chars(s, k) - most_k_chars(s, k - 1)
# Driver Program
s1 = "pqpqs"
k = 2
print(f"Total substrings with exactly {k} distinct characters: {exact_k_chars(s1, k)}")
s2 = "aabab"
k = 2
print(f"Total substrings with exactly {k} distinct characters: {exact_k_chars(s2, k)}")
# This code is contributed by Aman Kumar
using System;
using System.Collections.Generic;
class GFG {
// the number of subarrays with at most K distinct
// elements
static int most_k_chars(string s, int k)
{
if (s.Length == 0) {
return 0;
}
Dictionary<char, int> map
= new Dictionary<char, int>();
int num = 0, left = 0;
for (int i = 0; i < s.Length; i++) {
if (map.ContainsKey(s[i])) {
int val = map[s[i]];
map.Remove(s[i]);
map.Add(s[i], val + 1);
}
else
map.Add(s[i], 1);
while (map.Count > k) {
if (map.ContainsKey(s[left])) {
int val = map[s[left]];
map.Remove(s[left]);
map.Add(s[left], val - 1);
}
else
map.Add(s[left], -1);
if (map[s[left]] == 0) {
map.Remove(s[left]);
}
left++;
}
num += i - left + 1;
}
return num;
}
static int exact_k_chars(String s, int k)
{
return most_k_chars(s, k) - most_k_chars(s, k - 1);
}
public static void Main(string []args)
{
string s1 = "pqpqs";
int k = 2;
Console.WriteLine("Total substrings with exactly "
+ k + " distinct characters : "
+ exact_k_chars(s1, k));
string s2 = "aabab";
k = 2;
Console.WriteLine("Total substrings with exactly "
+ k + " distinct characters : "
+ exact_k_chars(s2, k));
}
}
// This code is contributed by garg28harsh.
function most_k_chars(s, k) {
if (!s) {
return 0;
}
const char_count = {};
let num = 0;
let left = 0;
for (let i = 0; i < s.length; i++) {
char_count[s[i]] = (char_count[s[i]] || 0) + 1;
while (Object.keys(char_count).length > k) {
char_count[s[left]] -= 1;
if (char_count[s[left]] === 0) {
delete char_count[s[left]];
}
left += 1;
}
num += i - left + 1;
}
return num;
}
function exact_k_chars(s, k) {
return most_k_chars(s, k) - most_k_chars(s, k - 1);
}
// Driver Program
const s1 = "pqpqs";
let k = 2;
console.log(`Total substrings with exactly ${k} distinct characters: ${exact_k_chars(s1, k)}`);
const s2 = "aabab";
k = 2;
console.log(`Total substrings with exactly ${k} distinct characters: ${exact_k_chars(s2, k)}`);
Output
Total substrings with exactly 2 distinct characters : 7 Total substrings with exactly 2 distinct characters : 9
Time Complexity: O(n)
Auxiliary Space: O(1)
Efficient Approach Without Map : The idea is to count all the subarrays with at most K distinct characters and then subtract all the subarrays with atmost K – 1 characters. That leaves us with count of subarrays with exactly K distinct characters. But in this Approach we are not using map instead vector of 26 size.
Below is the implementation of the above approach:
#include <iostream>
#include <vector>
using namespace std;
// Function to count the number of substrings with at most k distinct characters
int countSubstringsWithAtMostKDistinctChars(string &s, int k) {
int left = 0, right = 0, n = s.size(), distinctCount = 0, substringCount = 0;
// Vector to store the frequency of characters in the current substring
vector<int> charFrequency(26, 0);
while (right < n) {
int charIndex = s[right] - 'a';
charFrequency[charIndex]++;
// If the frequency becomes 1, it means a new distinct character is added
if (charFrequency[charIndex] == 1) {
distinctCount++;
}
// While the number of distinct characters exceeds k, move the left pointer
while (distinctCount > k) {
charFrequency[s[left] - 'a']--;
// If the frequency becomes 0, it means a distinct character is removed
if (charFrequency[s[left] - 'a'] == 0) {
distinctCount--;
}
left++;
}
// Add the count of substrings with at most k distinct characters
substringCount += (right - left + 1);
// Move the right pointer to expand the window
right++;
}
return substringCount;
}
// Function to count the number of substrings with exactly k distinct characters
int countSubstringsWithExactlyKDistinctChars(string str, int k) {
// Count substrings with at most k distinct characters
int countAtMostK = countSubstringsWithAtMostKDistinctChars(str, k);
// Count substrings with at most (k-1) distinct characters
int countAtMostKMinus1 = countSubstringsWithAtMostKDistinctChars(str, k - 1);
// The difference gives the count of substrings with exactly k distinct characters
return countAtMostK - countAtMostKMinus1;
}
int main() {
// Example usage
string inputString = "aacfssa";
int k = 3;
int result = countSubstringsWithExactlyKDistinctChars(inputString, k);
cout << "The number of substrings with exactly " << k << " distinct characters is: " << result << endl;
return 0;
}
import java.util.Arrays;
public class Main {
// Function to count the number of substrings with at most k distinct characters
static int countSubstringsWithAtMostKDistinctChars(String s, int k) {
int left = 0, right = 0, n = s.length(), distinctCount = 0, substringCount = 0;
// Array to store the frequency of characters in the current substring
int[] charFrequency = new int[26];
while (right < n) {
int charIndex = s.charAt(right) - 'a';
charFrequency[charIndex]++;
// If the frequency becomes 1, it means a new distinct character is added
if (charFrequency[charIndex] == 1) {
distinctCount++;
}
// While the number of distinct characters exceeds k, move the left pointer
while (distinctCount > k) {
charFrequency[s.charAt(left) - 'a']--;
// If the frequency becomes 0, it means a distinct character is removed
if (charFrequency[s.charAt(left) - 'a'] == 0) {
distinctCount--;
}
left++;
}
// Add the count of substrings with at most k distinct characters
substringCount += (right - left + 1);
// Move the right pointer to expand the window
right++;
}
return substringCount;
}
// Function to count the number of substrings with exactly k distinct characters
static int countSubstringsWithExactlyKDistinctChars(String str, int k) {
// Count substrings with at most k distinct characters
int countAtMostK = countSubstringsWithAtMostKDistinctChars(str, k);
// Count substrings with at most (k-1) distinct characters
int countAtMostKMinus1 = countSubstringsWithAtMostKDistinctChars(str, k - 1);
// The difference gives the count of substrings with exactly k distinct characters
return countAtMostK - countAtMostKMinus1;
}
public static void main(String[] args) {
// Example usage
String inputString = "aacfssa";
int k = 3;
int result = countSubstringsWithExactlyKDistinctChars(inputString, k);
System.out.println("The number of substrings with exactly " + k + " distinct characters is: " + result);
}
}
// This code is contributed by rambabuguphka
def count_substrings_with_at_most_k_distinct_chars(s, k):
left, right, n, distinct_count, substring_count = 0, 0, len(s), 0, 0
# List to store the frequency of characters in the current substring
char_frequency = [0] * 26
while right < n:
char_index = ord(s[right]) - ord('a')
char_frequency[char_index] += 1
# If the frequency becomes 1, it means a new distinct character is added
if char_frequency[char_index] == 1:
distinct_count += 1
# While the number of distinct characters exceeds k, move the left pointer
while distinct_count > k:
char_frequency[ord(s[left]) - ord('a')] -= 1
# If the frequency becomes 0, it means a distinct character is removed
if char_frequency[ord(s[left]) - ord('a')] == 0:
distinct_count -= 1
left += 1
# Add the count of substrings with at most k distinct characters
substring_count += (right - left + 1)
# Move the right pointer to expand the window
right += 1
return substring_count
def count_substrings_with_exactly_k_distinct_chars(s, k):
# Count substrings with at most k distinct characters
count_at_most_k = count_substrings_with_at_most_k_distinct_chars(s, k)
# Count substrings with at most (k-1) distinct characters
count_at_most_k_minus_1 = count_substrings_with_at_most_k_distinct_chars(
s, k - 1)
# The difference gives the count of substrings with exactly k distinct characters
return count_at_most_k - count_at_most_k_minus_1
def main():
# Example usage
input_string = "aacfssa"
k = 3
result = count_substrings_with_exactly_k_distinct_chars(input_string, k)
print("The number of substrings with exactly",
k, "distinct characters is:", result)
if __name__ == "__main__":
main()
using System;
class Program
{
static int CountSubstringsWithAtMostKDistinctChars(string s, int k)
{
int left = 0, right = 0, n = s.Length, distinctCount = 0, substringCount = 0;
// Array to store the frequency of characters in the current substring
int[] charFrequency = new int[26];
while (right < n)
{
int charIndex = s[right] - 'a';
charFrequency[charIndex]++;
// If the frequency becomes 1, a new distinct character is added
if (charFrequency[charIndex] == 1)
{
distinctCount++;
}
// While the number of distinct characters exceeds k, move the left pointer
while (distinctCount > k)
{
charFrequency[s[left] - 'a']--;
// If the frequency becomes 0, a distinct character is removed
if (charFrequency[s[left] - 'a'] == 0)
{
distinctCount--;
}
left++;
}
// Add the count of substrings with at most k distinct characters
substringCount += (right - left + 1);
// Move the right pointer to expand the window
right++;
}
return substringCount;
}
static int CountSubstringsWithExactlyKDistinctChars(string s, int k)
{
// Count substrings with at most k distinct characters
int countAtMostK = CountSubstringsWithAtMostKDistinctChars(s, k);
// Count substrings with at most (k-1) distinct characters
int countAtMostKMinus1 = CountSubstringsWithAtMostKDistinctChars(s, k - 1);
// The difference gives the count of substrings with exactly k distinct characters
return countAtMostK - countAtMostKMinus1;
}
static void Main(string[] args)
{
// Example usage
string inputString = "aacfssa";
int k = 3;
int result = CountSubstringsWithExactlyKDistinctChars(inputString, k);
Console.WriteLine("The number of substrings with exactly " + k + " distinct characters is: " + result);
}
}
// Function to count the number of substrings with at most k distinct characters
function countSubstringsWithAtMostKDistinctChars(s, k) {
let left = 0, right = 0, n = s.length, distinctCount = 0, substringCount = 0;
let charFrequency = new Array(26).fill(0); // Array to store the frequency of characters in the current substring
while (right < n) {
let charIndex = s.charCodeAt(right) - 'a'.charCodeAt(0); // Get the character index in the frequency array
charFrequency[charIndex]++; // Increment the frequency of the character
if (charFrequency[charIndex] === 1) {
distinctCount++; // If the frequency becomes 1, a new distinct character is added
}
// While the number of distinct characters exceeds k, move the left pointer
while (distinctCount > k) {
charFrequency[s.charCodeAt(left) - 'a'.charCodeAt(0)]--; // Decrement the frequency of the character at left pointer
if (charFrequency[s.charCodeAt(left) - 'a'.charCodeAt(0)] === 0) {
distinctCount--; // If the frequency becomes 0, a distinct character is removed
}
left++; // Move the left pointer
}
substringCount += (right - left + 1); // Add the count of substrings with at most k distinct characters
right++; // Move the right pointer to expand the window
}
return substringCount;
}
// Function to count the number of substrings with exactly k distinct characters
function countSubstringsWithExactlyKDistinctChars(str, k) {
// Count substrings with at most k distinct characters
let countAtMostK = countSubstringsWithAtMostKDistinctChars(str, k);
// Count substrings with at most (k-1) distinct characters
let countAtMostKMinus1 = countSubstringsWithAtMostKDistinctChars(str, k - 1);
// The difference gives the count of substrings with exactly k distinct characters
return countAtMostK - countAtMostKMinus1;
}
// Example usage
let inputString = "aacfssa";
let k = 3;
let result = countSubstringsWithExactlyKDistinctChars(inputString, k);
console.log("The number of substrings with exactly " + k + " distinct characters is: " + result);
Output
The number of substrings with exactly 3 distinct characters is: 5
Time Complexity: O(n)
Auxiliary Space: O(1)