每个字符的计数为 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
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)。
最佳方法:
经过非常仔细的观察,我们可以看到对长度的子串进行相同的检查就足够了在哪里是给定字符串中存在的不同字符的数量。
争论:
考虑一个长度为 'p' 的子串 S_{i+1}S_{i+2}\dots S_{i+p}。如果这个子串有 'm' 个不同的字符并且每个不同的字符恰好出现 'K' 次,那么子串的长度 'p' 由 p = K\times m 给出。自从 ' ' 始终是 'K' 的倍数,并且对于给定的字符串,迭代长度可被 'K' 整除并具有 m, 1 \le m \le 26 个不同字符的子字符串就足够了。我们将使用滑动窗口来迭代固定长度的子字符串。
解决方案:
- 查找给定字符串中存在的不同字符的数量。让它成为D。
- 对于每个 i, 1\le i\le D,执行以下操作
- 使用滑动窗口迭代长度为 $i \times K$ 的子串。
- 检查它们是否满足条件 - 子字符串中的所有不同字符恰好出现 K 次。
- 如果它们满足条件,则增加计数。
C++
#include
#include
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 是字符串的长度。