📌  相关文章
📜  计算字符串中一个字符频率超过另一个字符频率的子字符串

📅  最后修改于: 2021-09-07 05:25:11             🧑  作者: Mango

给定一个大小为N的字符串S仅由字符abc 组成,任务是找到给定字符串S的子串数,使得字符a的频率大于字符c的频率。

例子:

朴素方法:解决给定问题的最简单方法是生成给定字符串S 的所有可能子字符串,并计算字符‘a’计数大于字符‘c’计数的那些子字符串。检查所有子字符串后,打印总计数的值作为结果。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
// Function to find the number of
// substrings having the frequency of
// 'a' greater than frequency of 'c'
void countSubstrings(string& s)
{
    // Stores the size of the string
    int n = s.length();
 
    // Stores the resultant
    // count of substrings
    int ans = 0;
 
    // Traverse the given string
    for (int i = 0; i < n; i++) {
 
        // Store the difference between
        // frequency of 'a' and 'c'
        int cnt = 0;
 
        // Traverse all substrings
        // begining at index i
        for (int j = i; j < n; j++) {
            if (s[j] == 'a')
                cnt++;
            else if (s[j] == 'c')
                cnt--;
 
            // If the frequency of 'a'
            // is greater than 'c'
            if (cnt > 0) {
                ans++;
            }
        }
    }
 
    // Print the answer
    cout << ans;
}
 
// Drive Code
int main()
{
    string S = "abccaab";
    countSubstrings(S);
 
    return 0;
}


Java
// Java program for the above approach
public class GFG
{
     
// Function to find the number of
// substrings having the frequency of
// 'a' greater than frequency of 'c'
public static void countSubstrings(String s)
{
   
    // Stores the size of the string
    int n = s.length();
 
    // Stores the resultant
    // count of substrings
    int ans = 0;
 
    // Traverse the given string
    for (int i = 0; i < n; i++) {
 
        // Store the difference between
        // frequency of 'a' and 'c'
        int cnt = 0;
 
        // Traverse all substrings
        // begining at index i
        for (int j = i; j < n; j++) {
            if (s.charAt(j) == 'a')
                cnt++;
            else if (s.charAt(j) == 'c')
                cnt--;
 
            // If the frequency of 'a'
            // is greater than 'c'
            if (cnt > 0) {
                ans++;
            }
        }
    }
 
    // Print the answer
    System.out.println(ans);
}
 
// Drive Code
public static void main(String args[])
{
    String S = "abccaab";
    countSubstrings(S);
 
}
}
 
// This code is contributed by SoumikMondal


Python3
# python program for the above approach
 
# Function to find the number of
# substrings having the frequency of
# 'a' greater than frequency of 'c'
def countSubstrings(s):
   
    # Stores the size of the string
    n = len(s)
 
    # Stores the resultant
    # count of substrings
    ans = 0
 
    # Traverse the given string
    for i in range(n):
       
        # Store the difference between
        # frequency of 'a' and 'c'
        cnt = 0
 
        # Traverse all substrings
        # begining at index i
        for j in range(i, n):
            if (s[j] == 'a'):
                cnt += 1
            elif (s[j] == 'c'):
                cnt -= 1
 
            # If the frequency of 'a'
            # is greater than 'c'
            if (cnt > 0):
                ans+=1
 
    # Prthe answer
    print (ans)
 
# Drive Code
if __name__ == '__main__':
    S = "abccaab"
    countSubstrings(S)
 
# This code is contributed by mohit kumar 29.


Javascript


C++
// C++ program for the above approach
#include 
using namespace std;
 
// Function to update the segment Tree
void update(int ind, vector& segTree,
            int n)
{
    // Update the value of ind
    ind += n;
 
    // Increment the leaf node
    segTree[ind]++;
 
    for (; ind > 1; ind >>= 1) {
 
        // Update the parent nodes
        segTree[ind >> 1] = segTree[ind]
                            + segTree[ind ^ 1];
    }
}
 
// Function to get the sum of all the
// elements between low to high - 1
int query(int low, int high,
          vector& segTree, int n)
{
    // Initialize the leaf nodes of
    // the segment tree
    low += n;
    high += n;
 
    int ans = 0;
 
    while (low < high) {
 
        // Node lies completely in the
        // range of low to high
        if (low % 2) {
            ans += segTree[low];
            low++;
        }
 
        if (high % 2) {
            high--;
            ans += segTree[high];
        }
 
        // Update the value of nodes
        low >>= 1;
        high >>= 1;
    }
 
    return ans;
}
 
// Function to count the number of
// substrings which have frequency of
// 'a' greater than frequency of 'c'.
void countSubstrings(string& s)
{
    // Store the size of the string
    int n = s.length();
 
    // Intialize segment tree
    vector segTree(4 * n);
 
    int count = 0;
 
    // Update the initial value of
    // the count
    update(n, segTree, 2 * n);
 
    // Stores the required result
    int ans = 0;
 
    // Traverse the given string
    for (int i = 0; i < n; i++) {
 
        // Increment count
        if (s[i] == 'a')
            count++;
 
        // Decrement count
        else if (s[i] == 'c')
            count--;
 
        // Query the segment tree to
        // find the sum of all values
        // less than count
        int val = query(0, n + count,
                        segTree, 2 * n);
        ans += val;
 
        // Update the current value of
        // count in the segment tree
        update(n + count, segTree, 2 * n);
    }
 
    // Print the answer
    cout << ans;
}
 
// Driver Code
int main()
{
    string S = "abccaab";
    countSubstrings(S);
 
    return 0;
}


输出:
11

时间复杂度: O(N 2 )
辅助空间: O(1)

高效方法:上述方法也可以通过使用 Segment Tree 进行优化。这个想法是在段树节点中存储字符串S 的所有前缀的字符‘a’‘c’的频率差异。请按照以下步骤解决问题:

  • 初始化一个变量,比如count0 ,以存储字符‘a’‘c’频率之间的差异。
  • 初始化一个变量,比如ans0 ,以存储字符‘a’的频率大于‘c’的子串的计数。
  • 用全0初始化段树,这将在遍历字符串更新。
  • 由于字符‘a’‘c’的频率差异也可以为负,因此段树上的所有更新操作都将在将N添加到要更新的索引后完成,以避免出现负索引。
  • 更新段树中索引(0 + N)的值,因为计数的初始值为0
  • [0, N – 1]范围内遍历给定的字符串S并执行以下步骤:
    • 如果当前字符是 ‘a’,则将计数增加1 。否则,如果当前字符是“c”的,然后由1递减计数
    • 对线段树执行查询以找到小于count的所有值的总和,因为所有这些子字符串的频率‘a’大于‘c’并将返回的值存储在变量 say val 中
    • val的值添加到变量ans
    • 由索引处的值递增更新线段树被1(计数+ N)。
  • 完成上述步骤后,将ans的值打印为子串的结果计数。

下面是上述方法的实现:

C++

// C++ program for the above approach
#include 
using namespace std;
 
// Function to update the segment Tree
void update(int ind, vector& segTree,
            int n)
{
    // Update the value of ind
    ind += n;
 
    // Increment the leaf node
    segTree[ind]++;
 
    for (; ind > 1; ind >>= 1) {
 
        // Update the parent nodes
        segTree[ind >> 1] = segTree[ind]
                            + segTree[ind ^ 1];
    }
}
 
// Function to get the sum of all the
// elements between low to high - 1
int query(int low, int high,
          vector& segTree, int n)
{
    // Initialize the leaf nodes of
    // the segment tree
    low += n;
    high += n;
 
    int ans = 0;
 
    while (low < high) {
 
        // Node lies completely in the
        // range of low to high
        if (low % 2) {
            ans += segTree[low];
            low++;
        }
 
        if (high % 2) {
            high--;
            ans += segTree[high];
        }
 
        // Update the value of nodes
        low >>= 1;
        high >>= 1;
    }
 
    return ans;
}
 
// Function to count the number of
// substrings which have frequency of
// 'a' greater than frequency of 'c'.
void countSubstrings(string& s)
{
    // Store the size of the string
    int n = s.length();
 
    // Intialize segment tree
    vector segTree(4 * n);
 
    int count = 0;
 
    // Update the initial value of
    // the count
    update(n, segTree, 2 * n);
 
    // Stores the required result
    int ans = 0;
 
    // Traverse the given string
    for (int i = 0; i < n; i++) {
 
        // Increment count
        if (s[i] == 'a')
            count++;
 
        // Decrement count
        else if (s[i] == 'c')
            count--;
 
        // Query the segment tree to
        // find the sum of all values
        // less than count
        int val = query(0, n + count,
                        segTree, 2 * n);
        ans += val;
 
        // Update the current value of
        // count in the segment tree
        update(n + count, segTree, 2 * n);
    }
 
    // Print the answer
    cout << ans;
}
 
// Driver Code
int main()
{
    string S = "abccaab";
    countSubstrings(S);
 
    return 0;
}
输出:
11

时间复杂度: O(N*log N)
辅助空间: O(N)

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live