Count Substrings with at least one occurrence of first K alphabet
Last Updated :
14 Sep, 2023
Given a string S of size N and a positive integer K. The given string only consists of the first K English lowercase alphabets. The task is to find the number of substrings that contain at least one occurrence of all these K characters.
Examples:
Input: S = “abcabc”, K = 3
Output: 10
Explanation: The substrings containing at least one occurrence of the first three characters of English lowercase alphabets (a, b and c) are “abc”, “abca”, “abcab”, “abcabc”, “bca”, “bcab”, “bcabc”, “cab”, “cabc” and “abc”.
Input: S = “aaacb”, K = 4
Output: 0
Explanation: There is no substring that contains at least one occurrence of all first K characters of English lowercase alphabets (a, b, c and d)
An approach using Hashing and Two-Pointer approach:
The idea is to keep a two-pointer say start and end at the beginning of the string.
For every start, we’ll find the first valid substring which starts from index start and ends at index end. As this is the first valid substring starting from start but we can also include rest of the character from end index because we already satisfied the minimum criteria of validity. So there would be (N – end) total valid string for this start index.
We’ll keep adding all these count into result and finally return the result.
Follow the steps below to implement the above idea:
- Initialize a map for keeping the frequency of characters
- Initialize a variable start = 0, end = 0, and result = 0.
- Do it while the end is less than the size of the given string
- Increment the frequency of character at the end.
- Check if the size of the map becomes K
- Initiate a while loop unless the map size is equal to K.
- Increment the value of the result by N – end, because (N – end) substrings satisfy the given condition
- Decrement the frequency count of characters at the start of the map
- Check if the frequency count of the character at the start of the map becomes 0.
- If true, then remove this character from the map as this character will no longer exist in the valid substring for the new value of start.
- Move the start pointer to right by incrementing its value by 1
- Shift the end pointer to right by incrementing its value by 1.
- Otherwise, Increment the end pointer by 1.
- Return the value of the result
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
int numberOfSubstrings(string s, int K)
{
unordered_map< char , int > unmap;
int start = 0, end = 0, n = s.size(), result = 0;
while (end < n) {
unmap[s[end]]++;
if (unmap.size() == K) {
while (unmap.size() == K) {
result += n - end;
unmap[s[start]]--;
if (unmap[s[start]] == 0)
unmap.erase(s[start]);
start++;
}
end++;
}
else {
end++;
}
}
return result;
}
int main()
{
string S = "abcabc" ;
int K = 3;
cout << numberOfSubstrings(S, K);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static int numberOfSubstrings(String s, int K)
{
HashMap<Character, Integer> unmap = new HashMap<>();
int start = 0 , end = 0 , n = s.length(), result = 0 ;
while (end < n) {
unmap.put(s.charAt(end),
unmap.getOrDefault(s.charAt(end), 0 )
+ 1 );
if (unmap.size() == K) {
while (unmap.size() == K) {
result += n - end;
unmap.put(s.charAt(start),
unmap.get(s.charAt(start))
- 1 );
if (unmap.get(s.charAt(start)) == 0 ) {
unmap.remove(s.charAt(start));
}
start++;
}
end++;
}
else {
end++;
}
}
return result;
}
public static void main(String[] args)
{
String S = "abcabc" ;
int K = 3 ;
System.out.print(numberOfSubstrings(S, K));
}
}
|
Python3
def numberOfSubstrings(s, K):
unmap = {}
start = 0
end = 0
n = len (s)
result = 0
while (end < n):
unmap[s[end]] = unmap.get(s[end], 0 ) + 1
if len (unmap) = = K:
while len (unmap) = = K:
result + = n - end
unmap[s[start]] - = 1
if unmap[s[start]] = = 0 :
unmap.pop(s[start])
start + = 1
end + = 1
else :
end + = 1
return result
S = "abcabc"
K = 3
print (numberOfSubstrings(S, K))
|
C#
using System;
using System.Collections.Generic;
public class GFG {
static int numberOfSubstrings( string s, int K)
{
Dictionary< char , int > unmap = new Dictionary< char , int >();
int start = 0, end = 0, n = s.Length, result = 0;
while (end < n) {
if (unmap.ContainsKey(s[end])){
int temp = unmap[s[end]] + 1;
unmap[s[end]] = temp;
}
else {
unmap[s[end]] = 1;
}
if (unmap.Count == K) {
while (unmap.Count == K) {
result += n - end;
unmap[s[start]] = unmap[s[start]] - 1;
if (unmap[s[start]] == 0) {
unmap.Remove(s[start]);
}
start++;
}
end++;
}
else {
end++;
}
}
return result;
}
static public void Main()
{
string S = "abcabc" ;
int K = 3;
Console.Write(numberOfSubstrings(S, K));
}
}
|
Javascript
function numberOfSubstrings(s, K)
{
let unmap = {};
let start = 0, end = 0, n = s.length, result = 0;
while (end < n)
{
if (unmap[s[end]]) {
unmap[s[end]]++;
} else {
unmap[s[end]] = 1;
}
if (Object.keys(unmap).length == K)
{
while (Object.keys(unmap).length == K)
{
result += n - end;
unmap[s[start]]--;
if (unmap[s[start]] == 0)
delete unmap[s[start]];
start++;
}
end++;
}
else {
end++;
}
}
return result;
}
console.log(numberOfSubstrings( "abcabc" , 3));
|
Time Complexity: O(N)
Auxiliary Space: O(N)
Another Approach: Using sliding window technique
1)Initialize an array freq of size K to keep track of the frequency of each character in the window. Also, initialize a variable uniqueCount to 0 to keep track of the number of unique characters in the window, and a variable ans to 0 to keep track of the count of valid substrings.
2)Initialize two pointers left and right to 0, which represent the start and end of the current window.
3)While the right pointer is less than the length of the string, do the following:
- Update the frequency of the current character at the right pointer by incrementing the corresponding index in the freq array.
- If the frequency of the current character is 1 (i.e., this character was not previously present in the window), increment the uniqueCount variable.
- Check if uniqueCount is equal to K. If it is, it means that the current window contains all K characters, so we can count the number of valid substrings that can be formed using the current window ending at the right pointer. This count is equal to the length of the substring from the right pointer to the end of the string, which is s.size() – right.
- Slide the window to the right by incrementing the right pointer.
- If uniqueCount is not equal to K, continue sliding the window to the right until it does.
4)When the loop in step 3 ends, return the ans variable, which contains the count of valid substrings.
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
int numberOfSubstrings(string s, int K)
{
int freq[K] = { 0 };
int uniqueCount = 0;
int ans = 0;
int left = 0, right = 0;
while (right < s.size()) {
freq[s[right] - 'a' ]++;
if (freq[s[right] - 'a' ] == 1) {
uniqueCount++;
}
while (uniqueCount == K) {
ans += (s.size()
- right);
freq[s[left] - 'a' ]--;
if (freq[s[left] - 'a' ] == 0) {
uniqueCount--;
}
left++;
}
right++;
}
return ans;
}
int main()
{
string S = "abcabc" ;
int K = 3;
cout << numberOfSubstrings(S, K);
return 0;
}
|
Java
import java.util.HashMap;
public class Main {
public static int numberOfSubstrings(String s, int K) {
int [] freq = new int [K];
int uniqueCount = 0 ;
int ans = 0 ;
int left = 0 , right = 0 ;
while (right < s.length()) {
freq[s.charAt(right) - 'a' ]++;
if (freq[s.charAt(right) - 'a' ] == 1 ) {
uniqueCount++;
}
while (uniqueCount == K) {
ans += (s.length() - right);
freq[s.charAt(left) - 'a' ]--;
if (freq[s.charAt(left) - 'a' ] == 0 ) {
uniqueCount--;
}
left++;
}
right++;
}
return ans;
}
public static void main(String[] args) {
String S = "abcabc" ;
int K = 3 ;
System.out.println(numberOfSubstrings(S, K));
}
}
|
Python3
def numberOfSubstrings(s, K):
freq = [ 0 ] * K
uniqueCount = 0
ans = 0
left = 0
right = 0
while right < len (s):
freq[ ord (s[right]) - ord ( 'a' )] + = 1
if freq[ ord (s[right]) - ord ( 'a' )] = = 1 :
uniqueCount + = 1
while uniqueCount = = K:
ans + = len (s) - right
freq[ ord (s[left]) - ord ( 'a' )] - = 1
if freq[ ord (s[left]) - ord ( 'a' )] = = 0 :
uniqueCount - = 1
left + = 1
right + = 1
return ans
S = "abcabc"
K = 3
print (numberOfSubstrings(S, K))
|
C#
using System;
class Program
{
static int numberOfSubstrings( string s, int K)
{
int [] freq = new int [K];
int uniqueCount = 0;
int ans = 0;
int left = 0, right
= 0;
while (right < s.Length) {
freq[s[right] - 'a' ]++;
if (freq[s[right] - 'a' ] == 1) {
uniqueCount++;
}
while (uniqueCount == K) {
ans += (s.Length
- right);
freq[s[left] - 'a' ]--;
if (freq[s[left] - 'a' ] == 0) {
uniqueCount--;
}
left++;
}
right++;
}
return ans;
}
static void Main()
{
string S = "abcabc" ;
int K = 3;
Console.WriteLine(numberOfSubstrings(S, K));
}
}
|
Javascript
function numberOfSubstrings(s, K) {
const freq = new Array(K).fill(0);
let uniqueCount = 0;
let ans = 0;
let left = 0, right = 0;
while (right < s.length) {
freq[s[right].charCodeAt(0) - 97]++;
if (freq[s[right].charCodeAt(0) - 97] == 1) {
uniqueCount++;
}
while (uniqueCount == K) {
ans += (s.length
- right);
freq[s[left].charCodeAt(0) - 97]--;
if (freq[s[left].charCodeAt(0) - 97] == 0) {
uniqueCount--;
}
left++;
}
right++;
}
return ans;
}
const S = "abcabc" ;
const K = 3;
console.log(numberOfSubstrings(S, K));
|
Time Complexity: O(N)
Auxiliary Space: O(K)
Share your thoughts in the comments
Please Login to comment...