Open In App

Good characters

Last Updated : 17 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given a strings A of length N and an integer K. Consider any substring S of A, a character C is said good if: 2*(frequency of C in S) – Length of Substring = K find the sum of count of all good characters across all the substrings of string A.

Example:

Input: N=4 K=0 A=abcd
Output: 6

Input: N=4 K=-1 A=abac
Output: 4

Approach using Hashing and Prefix Sum:

The idea is to fix a character and count the number of substrings it is good for. This can be done by using prefix sums and a map to store the smallest character and its frequency in each range.

Here’s a step-by-step breakdown of the idea:

  1. Fix a character: Fix a character, say ‘a’. This means we are trying to find all substrings where ‘a’ is the smallest character and occurs exactly once.
  2. Count the number of substrings: For each fixed character (‘a’ in this case), count the number of substrings it is good for. A substring is considered good if the condition 2 * (frequency of in the substring) – Length of Substring = 2*(frequency of a in the substring)-Length of Substring=K is satisfied.
  3. Use prefix sum: Prefix sum are used to quickly calculate the sum of elements in a given range. In this case, we use prefix sums to keep track of the frequency of each character in the string.
  4. Use a map: A map is used to store the smallest character and its frequency in each range. This helps us quickly identify if the fixed character is the smallest in a given range and if it occurs exactly once.
  5. Repeat for all characters: We repeat steps 1-4 for all characters in the string. The total count of good characters is the sum of the counts for each character.

Step-by-step approach:

  • Initialize the answer (ans) to zero.
  • Iterate over each character (‘a’ to ‘z’).
  • For each character, maintain a frequency array (mp) initialized with one occurrence at the middle index.
  • Traverse the input string, updating the occurrence count and total at each step.
  • Use prefix sum array (prefixSum) to efficiently calculate the sum of characters in the current substring.
  • Update the answer by adding the count of good characters based on the conditions specified in the problem.
  • Output the final result.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
const int MAX_CHARS = 26;
int countGoodCharacters(string A, int K)
{
    int n = A.length();
    long long ans = 0;
 
    for (int o = 0; o < MAX_CHARS; o++) {
        int mp[2 * n + 1]
            = { 0 }; // Initialize frequency array
        mp[n]++; // Initialize with one occurrence to handle
                // empty substring case
 
        int occurrence = 0;
        int total = n;
        vector<int> prefixSum(n + 1, n);
 
        for (int i = 0; i < n; i++) {
            int x = (A[i] == 'a' + o) ? 1 : -1;
            occurrence += x;
            total += x;
            prefixSum[i + 1] = total;
            ans += mp[total - K];
 
            // Check for substrings with negative length
            if (K < 0 && (i + 1 + K >= 0)
                && (prefixSum[i + 1 + K] == total - K))
                ans--;
 
            mp[total]++;
        }
    }
 
    return ans;
}
 
int main()
{
    int N = 4, K = -1;
    string A = "abac";
 
    long long result = countGoodCharacters(A, K);
 
    // Output the result
    cout << result << endl;
 
    return 0;
}


Java




import java.util.*;
 
public class GoodCharacters {
 
    static final int MAX_CHARS = 26;
 
    static long countGoodCharacters(String A, int K) {
        int n = A.length();
        long ans = 0;
 
        for (int o = 0; o < MAX_CHARS; o++) {
            int[] mp = new int[2 * n + 1]; // Initialize frequency array
            Arrays.fill(mp, 0);
            mp[n]++; // Initialize with one occurrence to handle empty substring case
 
            int occurrence = 0;
            int total = n;
            int[] prefixSum = new int[n + 1];
            Arrays.fill(prefixSum, n);
 
            for (int i = 0; i < n; i++) {
                int x = (A.charAt(i) == 'a' + o) ? 1 : -1;
                occurrence += x;
                total += x;
                prefixSum[i + 1] = total;
                ans += mp[total - K];
 
                // Check for substrings with negative length
                if (K < 0 && (i + 1 + K >= 0) && (prefixSum[i + 1 + K] == total - K))
                    ans--;
 
                mp[total]++;
            }
        }
 
        return ans;
    }
 
    public static void main(String[] args) {
        int N = 4, K = -1;
        String A = "abac";
 
        long result = countGoodCharacters(A, K);
 
        // Output the result
        System.out.println(result);
    }
}
 
// This code is contributed by akshitaguprzj3


Python3




MAX_CHARS = 26
 
def count_good_characters(A, K):
    n = len(A)
    ans = 0
 
    for o in range(MAX_CHARS):
        mp = [0] * (2 * n + 1# Initialize frequency array
        mp[n] = 1  # Initialize with one occurrence to handle empty substring case
 
        occurrence = 0
        total = n
        prefix_sum = [n] * (n + 1)
 
        for i in range(n):
            x = 1 if A[i] == chr(ord('a') + o) else -1
            occurrence += x
            total += x
            prefix_sum[i + 1] = total
            ans += mp[total - K]
 
            # Check for substrings with negative length
            if K < 0 and (i + 1 + K >= 0) and (prefix_sum[i + 1 + K] == total - K):
                ans -= 1
 
            mp[total] += 1
 
    return ans
 
def main():
    N, K = 4, -1
    A = "abac"
 
    result = count_good_characters(A, K)
 
    # Output the result
    print(result)
 
if __name__ == "__main__":
    main()


C#




using System;
using System.Collections.Generic;
 
class MainClass
{
    const int MAX_CHARS = 26;
 
    static long CountGoodCharacters(string A, int K)
    {
        int n = A.Length;
        long ans = 0;
 
        for (int o = 0; o < MAX_CHARS; o++)
        {
            int[] mp = new int[2 * n + 1];
            Array.Fill(mp, 0); // Initialize frequency array
            mp[n]++; // Initialize with one occurrence to handle empty substring case
 
            int occurrence = 0;
            int total = n;
            List<int> prefixSum = new List<int>(new int[n + 1]);
            prefixSum[0] = n;
 
            for (int i = 0; i < n; i++)
            {
                int x = (A[i] == 'a' + o) ? 1 : -1;
                occurrence += x;
                total += x;
                prefixSum[i + 1] = total;
                ans += mp[total - K];
 
                // Check for substrings with negative length
                if (K < 0 && (i + 1 + K >= 0) && (prefixSum[i + 1 + K] == total - K))
                    ans--;
 
                mp[total]++;
            }
        }
 
        return ans;
    }
 
    public static void Main(string[] args)
    {
        int K = -1;
        string A = "abac";
 
        long result = CountGoodCharacters(A, K);
 
        // Output the result
        Console.WriteLine(result);
    }
}


Javascript




const MAX_CHARS = 26;
 
function countGoodCharacters(A, K) {
    const n = A.length;
    let ans = 0;
 
    for (let o = 0; o < MAX_CHARS; o++) {
        const mp = new Array(2 * n + 1).fill(0); // Initialize frequency array
        mp[n]++; // Initialize with one occurrence to handle empty substring case
 
        let occurrence = 0;
        let total = n;
        const prefixSum = new Array(n + 1).fill(0);
        prefixSum[0] = n;
 
        for (let i = 0; i < n; i++) {
            const x = A[i] === String.fromCharCode('a'.charCodeAt(0) + o) ? 1 : -1;
            occurrence += x;
            total += x;
            prefixSum[i + 1] = total;
            ans += mp[total - K];
 
            // Check for substrings with negative length
            if (K < 0 && i + 1 + K >= 0 && prefixSum[i + 1 + K] === total - K)
                ans--;
 
            mp[total]++;
        }
    }
 
    return ans;
}
 
// Test input
const K = -1;
const A = "abac";
 
const result = countGoodCharacters(A, K);
 
// Output the result
console.log(result);


Output

4

Time complexity: O(N * M), where N is the length of the input string s and M is the size of the alphabet (26 characters).
Auxiliary Space: O(M), where M is the size of the alphabet.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads