Given a string s
and three integers maxLetters
, minSize
, and maxSize
, find the maximum number of occurrences of any substring of s
that meets the following criteria:
minSize
and maxSize
(inclusive).maxLetters
unique letters.s
.
Constraints:
s.length
≤ 105maxLetters
≤ 26minSize
≤ maxSize
≤ min(26, s.length
)s
consists only of lowercase English letters.
To solve this problem, the initial idea is to check all possible substrings of s
that have a length between minSize
and maxSize
, count their occurrences, and track the maximum. However, this brute-force approach is inefficient because the number of substrings grows rapidly with the length of s
.
Upon closer inspection, we can optimize by considering that shorter substrings are more likely to repeat. Therefore, we focus on substrings of length minSize
only, since any longer substring will occur less frequently. For each substring, we check if it has at most maxLetters
unique characters. We use a hash map to count occurrences efficiently.
By narrowing our search to fixed-length substrings and using a sliding window technique, we can process the string in linear time, making the solution practical even for large inputs.
The solution involves the following steps:
minSize
to iterate through s
. At each position, we extract the substring and count its unique characters.
maxLetters
, the substring is valid.
We do not need to consider substrings longer than minSize
because any such substring can appear at most as many times as its minSize
-length prefix, so the maximum frequency will always be for a substring of length minSize
.
Input: s = "aababcaab"
, maxLetters = 2
, minSize = 3
, maxSize = 4
Let's walk through the steps:
s
:
"aab"
(unique letters: 2) → valid"aba"
(unique letters: 2) → valid"bab"
(unique letters: 2) → valid"abc"
(unique letters: 3) → invalid"bca"
(unique letters: 3) → invalid"caa"
(unique letters: 2) → valid"aab"
(unique letters: 2) → valid"aab"
: 2 times"aba"
: 1 time"bab"
: 1 time"caa"
: 1 time"aab"
occurs most frequently among valid substrings.Brute-force approach:
s
, since all substrings between minSize
and maxSize
are checked.minSize
and count unique letters for each window. Since minSize
is at most 26, this is effectively O(N).
By focusing on substrings of length minSize
and using a sliding window, we drastically reduce the number of substrings to check. A hash map allows us to count occurrences efficiently, and checking unique letters ensures we only consider valid substrings. This approach leverages string properties and hash-based counting to solve the problem elegantly and efficiently.
from collections import defaultdict
class Solution:
def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int:
count = defaultdict(int)
for i in range(len(s) - minSize + 1):
sub = s[i:i + minSize]
if len(set(sub)) <= maxLetters:
count[sub] += 1
return max(count.values() or [0])
#include <unordered_map>
#include <unordered_set>
#include <string>
using namespace std;
class Solution {
public:
int maxFreq(string s, int maxLetters, int minSize, int maxSize) {
unordered_map<string, int> count;
int n = s.size();
for (int i = 0; i <= n - minSize; ++i) {
string sub = s.substr(i, minSize);
unordered_set<char> unique(sub.begin(), sub.end());
if (unique.size() <= maxLetters) {
count[sub]++;
}
}
int res = 0;
for (auto &p : count) {
if (p.second > res) res = p.second;
}
return res;
}
};
import java.util.*;
class Solution {
public int maxFreq(String s, int maxLetters, int minSize, int maxSize) {
Map<String, Integer> count = new HashMap<>();
int n = s.length();
for (int i = 0; i <= n - minSize; i++) {
String sub = s.substring(i, i + minSize);
Set<Character> unique = new HashSet<>();
for (char c : sub.toCharArray()) unique.add(c);
if (unique.size() <= maxLetters) {
count.put(sub, count.getOrDefault(sub, 0) + 1);
}
}
int res = 0;
for (int val : count.values()) {
res = Math.max(res, val);
}
return res;
}
}
/**
* @param {string} s
* @param {number} maxLetters
* @param {number} minSize
* @param {number} maxSize
* @return {number}
*/
var maxFreq = function(s, maxLetters, minSize, maxSize) {
const count = new Map();
for (let i = 0; i <= s.length - minSize; i++) {
const sub = s.substring(i, i + minSize);
const unique = new Set(sub);
if (unique.size <= maxLetters) {
count.set(sub, (count.get(sub) || 0) + 1);
}
}
let res = 0;
for (let val of count.values()) {
res = Math.max(res, val);
}
return res;
};