📌  相关文章
📜  每个字符的计数为 k 的子串数

📅  最后修改于: 2022-05-13 01:57:07.361000             🧑  作者: Mango

每个字符的计数为 k 的子串数

给定一个字符串和一个整数 k,找出其中所有不同字符恰好出现 k 次的子字符串的数量。

例子:

Input : s = "aabbcc"
        k = 2 
Output : 6
The substrings are aa, bb, cc,
aabb, bbcc and aabbcc.

Input : s = "aabccc"
        k = 2
Output : 3
There are three substrings aa, 
cc and cc

这个想法是遍历所有子字符串。我们固定一个起点,从选取的点开始遍历所有子串,我们不断增加所有字符的频率。如果所有频率都变为 k,我们增加结果。如果任何频率的计数超过 k,我们就中断并改变起点。

C++
// C++ program to count number of substrings
// with counts of distinct characters as k.
#include 
using namespace std;
const int MAX_CHAR = 26;
 
// Returns true if all values
// in freq[] are either 0 or k.
bool check(int freq[], int k)
{
    for (int i = 0; i < MAX_CHAR; i++)
        if (freq[i] && freq[i] != k)
            return false;
    return true;
}
 
// Returns count of substrings where frequency
// of every present character is k
int substrings(string s, int k)
{
    int res = 0;  // Initialize result
 
    // Pick a starting point
    for (int i = 0; s[i]; i++) {
 
        // Initialize all frequencies as 0
        // for this starting point
        int freq[MAX_CHAR] = { 0 };
 
        // One by one pick ending points
        for (int j = i; s[j]; j++) {
  
            // Increment frequency of current char
            int index = s[j] - 'a';
            freq[index]++;
 
            // If frequency becomes more than
            // k, we can't have more substrings
            // starting with i
            if (freq[index] > k)
                break;
 
            // If frequency becomes k, then check
            // other frequencies as well.
            else if (freq[index] == k &&
                  check(freq, k) == true)
                res++;
        }
    }
    return res;
}
 
// Driver code
int main()
{
    string s = "aabbcc";
    int k = 2;
    cout << substrings(s, k) << endl;
 
    s = "aabbc";
    k = 2;
    cout << substrings(s, k) << endl;
}


Java
// Java program to count number of substrings
// with counts of distinct characters as k.
class GFG
{
 
static int MAX_CHAR = 26;
 
// Returns true if all values
// in freq[] are either 0 or k.
static boolean check(int freq[], int k)
{
    for (int i = 0; i < MAX_CHAR; i++)
        if (freq[i] !=0 && freq[i] != k)
            return false;
    return true;
}
 
// Returns count of substrings where frequency
// of every present character is k
static int substrings(String s, int k)
{
    int res = 0; // Initialize result
 
    // Pick a starting point
    for (int i = 0; i< s.length(); i++)
    {
 
        // Initialize all frequencies as 0
        // for this starting point
        int freq[] = new int[MAX_CHAR];
 
        // One by one pick ending points
        for (int j = i; j k)
                break;
 
            // If frequency becomes k, then check
            // other frequencies as well.
            else if (freq[index] == k &&
                check(freq, k) == true)
                res++;
        }
    }
    return res;
}
 
// Driver code
public static void main(String[] args)
{
    String s = "aabbcc";
    int k = 2;
    System.out.println(substrings(s, k));
 
    s = "aabbc";
    k = 2;
    System.out.println(substrings(s, k));
}
}
 
// This code has been contributed by 29AjayKumar


Python3
# Python3 program to count number of substrings
# with counts of distinct characters as k.
 
MAX_CHAR = 26
 
# Returns true if all values
# in freq[] are either 0 or k.
def check(freq, k):
    for i in range(0, MAX_CHAR):
        if(freq[i] and freq[i] != k):
            return False
    return True
 
# Returns count of substrings where
# frequency of every present character is k
def substrings(s, k):
    res = 0 # Initialize result
 
    # Pick a starting point
    for i in range(0, len(s)):
 
        # Initialize all frequencies as 0
        # for this starting point
        freq = [0] * MAX_CHAR
 
        # One by one pick ending points
        for j in range(i, len(s)):
             
            # Increment frequency of current char
            index = ord(s[j]) - ord('a')
            freq[index] += 1
 
            # If frequency becomes more than
            # k, we can't have more substrings
            # starting with i
            if(freq[index] > k):
                break
             
            # If frequency becomes k, then check
            # other frequencies as well
            elif(freq[index] == k and
                 check(freq, k) == True):
                res += 1
             
    return res
 
# Driver Code
if __name__ == "__main__":
    s = "aabbcc"
    k = 2
    print(substrings(s, k))
 
    s = "aabbc";
    k = 2;
    print(substrings(s, k))
 
# This code is contributed
# by Sairahul Jella


C#
// C# program to count number of substrings
// with counts of distinct characters as k.
using System;
 
class GFG
{
 
static int MAX_CHAR = 26;
 
// Returns true if all values
// in freq[] are either 0 or k.
static bool check(int []freq, int k)
{
    for (int i = 0; i < MAX_CHAR; i++)
        if (freq[i] != 0 && freq[i] != k)
            return false;
    return true;
}
 
// Returns count of substrings where frequency
// of every present character is k
static int substrings(String s, int k)
{
    int res = 0; // Initialize result
 
    // Pick a starting point
    for (int i = 0; i < s.Length; i++)
    {
 
        // Initialize all frequencies as 0
        // for this starting point
        int []freq = new int[MAX_CHAR];
 
        // One by one pick ending points
        for (int j = i; j < s.Length; j++)
        {
 
            // Increment frequency of current char
            int index = s[j] - 'a';
            freq[index]++;
 
            // If frequency becomes more than
            // k, we can't have more substrings
            // starting with i
            if (freq[index] > k)
                break;
 
            // If frequency becomes k, then check
            // other frequencies as well.
            else if (freq[index] == k &&
                check(freq, k) == true)
                res++;
        }
    }
    return res;
}
 
// Driver code
public static void Main(String[] args)
{
    String s = "aabbcc";
    int k = 2;
    Console.WriteLine(substrings(s, k));
 
    s = "aabbc";
    k = 2;
    Console.WriteLine(substrings(s, k));
}
}
 
/* This code contributed by PrinciRaj1992 */


PHP
 $k)
                break;
 
            // If frequency becomes k, then check
            // other frequencies as well.
            else if ($freq[$index] == $k &&
                check($freq, $k) == true)
                $res++;
        }
    }
    return $res;
}
 
// Driver code
$s = "aabbcc";
$k = 2;
echo substrings($s, $k)."\n";
$s = "aabbc";
$k = 2;
echo substrings($s, $k)."\n";
 
// This code is contributed by Ita_c.
?>


Javascript


C++
#include 
#include 
#include 
#include 
 
int min(int a, int b) { return a < b ? a : b; }
 
using namespace std;
 
bool have_same_frequency(map& freq, int k)
{
    for (auto& pair : freq) {
        if (pair.second != k && pair.second != 0) {
            return false;
        }
    }
    return true;
}
 
int count_substrings(string s, int k)
{
    int count = 0;
    int distinct = (set(s.begin(), s.end())).size();
    for (int length = 1; length <= distinct; length++) {
        int window_length = length * k;
        map freq;
        int window_start = 0;
        int window_end = window_start + window_length - 1;
        for (int i = window_start;
             i <= min(window_end, s.length() - 1); i++) {
            freq[s[i]]++;
        }
        while (window_end < s.length()) {
            if (have_same_frequency(freq, k)) {
                count++;
            }
            freq[s[window_start]]--;
            window_start++;
            window_end++;
            if (window_length < s.length()) {
                freq[s[window_end]]++;
            }
        }
    }
    return count;
}
 
int main()
{
    string s = "aabbcc";
    int k = 2;
    cout << count_substrings(s, k) << endl;
    s = "aabbc";
    k = 2;
    cout << count_substrings(s, k) << endl;
    return 0;
}


C
#include 
#include 
#include 
 
int min(int a, int b) { return a < b ? a : b; }
 
bool have_same_frequency(int freq[], int k)
{
    for (int i = 0; i < 26; i++) {
        if (freq[i] != 0 && freq[i] != k) {
            return false;
        }
    }
    return true;
}
 
int count_substrings(char* s, int n, int k)
{
    int count = 0;
    int distinct = 0;
    bool have[26] = { false };
    for (int i = 0; i < n; i++) {
        have[s[i] - 'a'] = true;
    }
    for (int i = 0; i < 26; i++) {
        if (have[i]) {
            distinct++;
        }
    }
    for (int length = 1; length <= distinct; length++) {
        int window_length = length * k;
        int freq[26] = { 0 };
        int window_start = 0;
        int window_end = window_start + window_length - 1;
        for (int i = window_start;
             i <= min(window_end, n - 1); i++) {
            freq[s[i] - 'a']++;
        }
        while (window_end < n) {
            if (have_same_frequency(freq, k)) {
                count++;
            }
            freq[s[window_start] - 'a']--;
            window_start++;
            window_end++;
            if (window_end < n) {
                freq[s[window_end] - 'a']++;
            }
        }
    }
    return count;
}
 
int main()
{
    char* s = "aabbcc";
    int k = 2;
    printf("%d\n", count_substrings(s, 6, k));
    s = "aabbc";
    k = 2;
    printf("%d\n", count_substrings(s, 5, k));
    return 0;
}


Java
import java.util.*;
 
class GFG {
 
    static boolean have_same_frequency(int[] freq, int k)
    {
        for (int i = 0; i < 26; i++) {
            if (freq[i] != 0 && freq[i] != k) {
                return false;
            }
        }
        return true;
    }
 
    static int count_substrings(String s, int k)
    {
        int count = 0;
        int distinct = 0;
        boolean[] have = new boolean[26];
        Arrays.fill(have, false);
        for (int i = 0; i < s.length(); i++) {
            have[((int)(s.charAt(i) - 'a'))] = true;
        }
        for (int i = 0; i < 26; i++) {
            if (have[i]) {
                distinct++;
            }
        }
        for (int length = 1; length <= distinct; length++) {
            int window_length = length * k;
            int[] freq = new int[26];
            Arrays.fill(freq, 0);
            int window_start = 0;
            int window_end
                = window_start + window_length - 1;
            for (int i = window_start;
                 i <= Math.min(window_end, s.length() - 1);
                 i++) {
                freq[((int)(s.charAt(i) - 'a'))]++;
            }
            while (window_end < s.length()) {
                if (have_same_frequency(freq, k)) {
                    count++;
                }
                freq[(
                    (int)(s.charAt(window_start) - 'a'))]--;
                window_start++;
                window_end++;
                if (window_end < s.length()) {
                    freq[((int)(s.charAt(window_end)
                                - 'a'))]++;
                }
            }
        }
        return count;
    }
    public static void main(String[] args)
    {
        String s = "aabbcc";
        int k = 2;
        System.out.println(count_substrings(s, k));
        s = "aabbc";
        k = 2;
        System.out.println(count_substrings(s, k));
    }
}


Python3
from collections import defaultdict
 
 
def have_same_frequency(freq: defaultdict, k: int):
    return all([freq[i] == k or freq[i] == 0 for i in freq])
 
 
def count_substrings(s: str, k: int) -> int:
    count = 0
    distinct = len(set([i for i in s]))
    for length in range(1, distinct + 1):
        window_length = length * k
        freq = defaultdict(int)
        window_start = 0
        window_end = window_start + window_length - 1
        for i in range(window_start, min(window_end + 1, len(s))):
            freq[s[i]] += 1
        while window_end < len(s):
            if have_same_frequency(freq, k):
                count += 1
            freq[s[window_start]] -= 1
            window_start += 1
            window_end += 1
            if window_end < len(s):
                freq[s[window_end]] += 1
    return count
 
 
if __name__ == '__main__':
    s = "aabbcc"
    k = 2
    print(count_substrings(s, k))
    s = "aabbc"
    k = 2
    print(count_substrings(s, k))


C#
using System;
 
class GFG{
 
static bool have_same_frequency(int[] freq, int k)
{
    for(int i = 0; i < 26; i++)
    {
        if (freq[i] != 0 && freq[i] != k)
        {
            return false;
        }
    }
    return true;
}
 
static int count_substrings(string s, int k)
{
    int count = 0;
    int distinct = 0;
    bool[] have = new bool[26];
    Array.Fill(have, false);
     
    for(int i = 0; i < s.Length; i++)
    {
        have[((int)(s[i] - 'a'))] = true;
    }
     
    for(int i = 0; i < 26; i++)
    {
        if (have[i])
        {
            distinct++;
        }
    }
     
    for(int length = 1; length <= distinct; length++)
    {
        int window_length = length * k;
        int[] freq = new int[26];
        Array.Fill(freq, 0);
        int window_start = 0;
        int window_end = window_start +
                         window_length - 1;
                          
        for(int i = window_start;
                i <= Math.Min(window_end, s.Length - 1);
                i++)
        {
            freq[((int)(s[i] - 'a'))]++;
        }
        while (window_end < s.Length)
        {
            if (have_same_frequency(freq, k))
            {
                count++;
            }
            freq[((int)(s[window_start] - 'a'))]--;
            window_start++;
            window_end++;
             
            if (window_end < s.Length)
            {
                freq[((int)(s[window_end] - 'a'))]++;
            }
        }
    }
    return count;
}
 
// Driver code
public static void Main(string[] args)
{
    string s = "aabbcc";
    int k = 2;
    Console.WriteLine(count_substrings(s, k));
     
    s = "aabbc";
    k = 2;
    Console.WriteLine(count_substrings(s, k));
}
}
 
// This code is contributed by gaurav01


Javascript


输出
6
3

时间复杂度: O(n*n) 其中 n 是输入字符串的长度。函数Check() 正在运行一个从 0 到 MAX_CHAR(即,始终为 26)的恒定长度循环,因此此函数check() 在 O(MAX_CHAR) 时间内运行,因此时间复杂度为 O(MAX_CHAR*n*n)=O( n^2)。

最佳方法:

经过非常仔细的观察,我们可以看到对长度的子串进行相同的检查就足够了K\times i,\ \forall\ i\isin[1, D]          在哪里D         是给定字符串中存在的不同字符的数量。

争论:

考虑一个长度为 'p' 的子串 S_{i+1}S_{i+2}\dots S_{i+p}。如果这个子串有 'm' 个不同的字符并且每个不同的字符恰好出现 'K' 次,那么子串的长度 'p' 由 p = K\times m 给出。自从 ' p         ' 始终是 'K' 的倍数,并且1\le m\le 26         对于给定的字符串,迭代长度可被 'K' 整除并具有 m, 1 \le m \le 26 个不同字符的子字符串就足够了。我们将使用滑动窗口来迭代固定长度的子字符串。

解决方案:

  • 查找给定字符串中存在的不同字符的数量。让它成为D。
  • 对于每个 i, 1\le i\le D,执行以下操作
    • 使用滑动窗口迭代长度为 $i \times K$ 的子串。
    • 检查它们是否满足条件 - 子字符串中的所有不同字符恰好出现 K 次。
    • 如果它们满足条件,则增加计数。

C++

#include 
#include 
#include 
#include 
 
int min(int a, int b) { return a < b ? a : b; }
 
using namespace std;
 
bool have_same_frequency(map& freq, int k)
{
    for (auto& pair : freq) {
        if (pair.second != k && pair.second != 0) {
            return false;
        }
    }
    return true;
}
 
int count_substrings(string s, int k)
{
    int count = 0;
    int distinct = (set(s.begin(), s.end())).size();
    for (int length = 1; length <= distinct; length++) {
        int window_length = length * k;
        map freq;
        int window_start = 0;
        int window_end = window_start + window_length - 1;
        for (int i = window_start;
             i <= min(window_end, s.length() - 1); i++) {
            freq[s[i]]++;
        }
        while (window_end < s.length()) {
            if (have_same_frequency(freq, k)) {
                count++;
            }
            freq[s[window_start]]--;
            window_start++;
            window_end++;
            if (window_length < s.length()) {
                freq[s[window_end]]++;
            }
        }
    }
    return count;
}
 
int main()
{
    string s = "aabbcc";
    int k = 2;
    cout << count_substrings(s, k) << endl;
    s = "aabbc";
    k = 2;
    cout << count_substrings(s, k) << endl;
    return 0;
}

C

#include 
#include 
#include 
 
int min(int a, int b) { return a < b ? a : b; }
 
bool have_same_frequency(int freq[], int k)
{
    for (int i = 0; i < 26; i++) {
        if (freq[i] != 0 && freq[i] != k) {
            return false;
        }
    }
    return true;
}
 
int count_substrings(char* s, int n, int k)
{
    int count = 0;
    int distinct = 0;
    bool have[26] = { false };
    for (int i = 0; i < n; i++) {
        have[s[i] - 'a'] = true;
    }
    for (int i = 0; i < 26; i++) {
        if (have[i]) {
            distinct++;
        }
    }
    for (int length = 1; length <= distinct; length++) {
        int window_length = length * k;
        int freq[26] = { 0 };
        int window_start = 0;
        int window_end = window_start + window_length - 1;
        for (int i = window_start;
             i <= min(window_end, n - 1); i++) {
            freq[s[i] - 'a']++;
        }
        while (window_end < n) {
            if (have_same_frequency(freq, k)) {
                count++;
            }
            freq[s[window_start] - 'a']--;
            window_start++;
            window_end++;
            if (window_end < n) {
                freq[s[window_end] - 'a']++;
            }
        }
    }
    return count;
}
 
int main()
{
    char* s = "aabbcc";
    int k = 2;
    printf("%d\n", count_substrings(s, 6, k));
    s = "aabbc";
    k = 2;
    printf("%d\n", count_substrings(s, 5, k));
    return 0;
}

Java

import java.util.*;
 
class GFG {
 
    static boolean have_same_frequency(int[] freq, int k)
    {
        for (int i = 0; i < 26; i++) {
            if (freq[i] != 0 && freq[i] != k) {
                return false;
            }
        }
        return true;
    }
 
    static int count_substrings(String s, int k)
    {
        int count = 0;
        int distinct = 0;
        boolean[] have = new boolean[26];
        Arrays.fill(have, false);
        for (int i = 0; i < s.length(); i++) {
            have[((int)(s.charAt(i) - 'a'))] = true;
        }
        for (int i = 0; i < 26; i++) {
            if (have[i]) {
                distinct++;
            }
        }
        for (int length = 1; length <= distinct; length++) {
            int window_length = length * k;
            int[] freq = new int[26];
            Arrays.fill(freq, 0);
            int window_start = 0;
            int window_end
                = window_start + window_length - 1;
            for (int i = window_start;
                 i <= Math.min(window_end, s.length() - 1);
                 i++) {
                freq[((int)(s.charAt(i) - 'a'))]++;
            }
            while (window_end < s.length()) {
                if (have_same_frequency(freq, k)) {
                    count++;
                }
                freq[(
                    (int)(s.charAt(window_start) - 'a'))]--;
                window_start++;
                window_end++;
                if (window_end < s.length()) {
                    freq[((int)(s.charAt(window_end)
                                - 'a'))]++;
                }
            }
        }
        return count;
    }
    public static void main(String[] args)
    {
        String s = "aabbcc";
        int k = 2;
        System.out.println(count_substrings(s, k));
        s = "aabbc";
        k = 2;
        System.out.println(count_substrings(s, k));
    }
}

Python3

from collections import defaultdict
 
 
def have_same_frequency(freq: defaultdict, k: int):
    return all([freq[i] == k or freq[i] == 0 for i in freq])
 
 
def count_substrings(s: str, k: int) -> int:
    count = 0
    distinct = len(set([i for i in s]))
    for length in range(1, distinct + 1):
        window_length = length * k
        freq = defaultdict(int)
        window_start = 0
        window_end = window_start + window_length - 1
        for i in range(window_start, min(window_end + 1, len(s))):
            freq[s[i]] += 1
        while window_end < len(s):
            if have_same_frequency(freq, k):
                count += 1
            freq[s[window_start]] -= 1
            window_start += 1
            window_end += 1
            if window_end < len(s):
                freq[s[window_end]] += 1
    return count
 
 
if __name__ == '__main__':
    s = "aabbcc"
    k = 2
    print(count_substrings(s, k))
    s = "aabbc"
    k = 2
    print(count_substrings(s, k))

C#

using System;
 
class GFG{
 
static bool have_same_frequency(int[] freq, int k)
{
    for(int i = 0; i < 26; i++)
    {
        if (freq[i] != 0 && freq[i] != k)
        {
            return false;
        }
    }
    return true;
}
 
static int count_substrings(string s, int k)
{
    int count = 0;
    int distinct = 0;
    bool[] have = new bool[26];
    Array.Fill(have, false);
     
    for(int i = 0; i < s.Length; i++)
    {
        have[((int)(s[i] - 'a'))] = true;
    }
     
    for(int i = 0; i < 26; i++)
    {
        if (have[i])
        {
            distinct++;
        }
    }
     
    for(int length = 1; length <= distinct; length++)
    {
        int window_length = length * k;
        int[] freq = new int[26];
        Array.Fill(freq, 0);
        int window_start = 0;
        int window_end = window_start +
                         window_length - 1;
                          
        for(int i = window_start;
                i <= Math.Min(window_end, s.Length - 1);
                i++)
        {
            freq[((int)(s[i] - 'a'))]++;
        }
        while (window_end < s.Length)
        {
            if (have_same_frequency(freq, k))
            {
                count++;
            }
            freq[((int)(s[window_start] - 'a'))]--;
            window_start++;
            window_end++;
             
            if (window_end < s.Length)
            {
                freq[((int)(s[window_end] - 'a'))]++;
            }
        }
    }
    return count;
}
 
// Driver code
public static void Main(string[] args)
{
    string s = "aabbcc";
    int k = 2;
    Console.WriteLine(count_substrings(s, k));
     
    s = "aabbc";
    k = 2;
    Console.WriteLine(count_substrings(s, k));
}
}
 
// This code is contributed by gaurav01

Javascript


输出
6
3

时间复杂度: O(N * D) 其中 D 是字符串中存在的不同字符的数量,N 是字符串的长度。