- Interview Questions
- /
- Problems
- /
- Maximum Number of Occurrences of a Substring
Maximum Number of Occurrences of a Substring
Count the occurrences of the most frequent substring with few enough distinct letters and a length in range. The real test is noticing that only the shortest allowed length matters. Solve it below in Python or JavaScript, then read the walkthrough.
Problem
You're given a string s and three integers maxLetters, minSize and maxSize.
A substring of s qualifies if:
- it contains at most
maxLettersdistinct characters, and - its length is between
minSizeandmaxSize, inclusive.
Return the largest number of times any single qualifying substring occurs in s. Occurrences may overlap: in "aaaa", the substring "aa" occurs 3 times. If no substring qualifies, return 0.
Example 1
- Input
- s = "aababcaab", maxLetters = 2, minSize = 3, maxSize = 4
- Output
- 2
"aab" has 2 distinct letters and appears at index 0 and index 6. No qualifying substring appears more often.
Example 2
- Input
- s = "zzzzz", maxLetters = 1, minSize = 2, maxSize = 3
- Output
- 4
"zz" starts at indices 0, 1, 2 and 3. Overlapping occurrences all count.
Example 3
- Input
- s = "abcde", maxLetters = 2, minSize = 3, maxSize = 3
- Output
- 0
Every length-3 substring has 3 distinct letters, so nothing qualifies.
Constraints
- 1 ≤ s.length ≤ 10⁵
- 1 ≤ maxLetters ≤ 26
- 1 ≤ minSize ≤ maxSize ≤ min(26, s.length)
- s contains only lowercase English letters.
Practice
Runs 13 tests in your browser. Python loads on the first run (about 6 MB, then cached). Press ⌘/Ctrl + Enter to run.
Get asked Maximum Number of Occurrences of a Substring in a real interview?
Interview Solver gives you a working solution live, during your actual coding interview. Invisible to screensharing.
How to solve Maximum Number of Occurrences of a Substring
Pattern: Fixed-size sliding window with a frequency map
The key observation is that maxSize doesn't matter. Take any qualifying substring t longer than minSize. Every place t occurs, its first minSize characters occur too, and that shorter prefix has no more distinct letters than t. So the prefix qualifies and appears at least as often as t. The best answer is always achieved by some substring of length exactly minSize.
That turns the problem into: slide a window of length minSize across s, keep a count of each letter in the window to know how many distinct letters it has, and tally every window that has at most maxLetters distinct letters. The answer is the highest tally.
Approach 1: Every length from minSize to maxSize
For each length L in the range and each start index, take the substring, count its distinct letters, and tally it if it qualifies. Correct, but it does work for every length even though only one length can matter.
Time O(n · (maxSize - minSize + 1) · maxSize) · Space O(n · maxSize)
Approach 2: Only length minSize, recount each window
Use the observation above and look only at windows of length minSize, building a set of each window to count distinct letters. Much faster, though each window still costs O(minSize) to inspect.
Time O(n · minSize) · Space O(n · minSize)
Approach 3: Sliding window with letter counts
Keep letters, a count per character in the current window, and distinct, how many counts are non-zero.
- For each
right, adds[right](if its count goes from 0 to 1, incrementdistinct). - If the window is longer than
minSize, removes[right - minSize](if its count drops to 0, decrementdistinct). - Once the window has length
minSizeanddistinct <= maxLetters, increment the tally for that substring.
Return the largest tally, or 0 if nothing was tallied.
Time O(n · minSize) for slicing and hashing windows, O(n) for the window bookkeeping · Space O(n · minSize)
| Approach | Time | Space |
|---|---|---|
| Every length from minSize to maxSize | O(n · (maxSize - minSize + 1) · maxSize) | O(n · maxSize) |
| Only length minSize, recount each window | O(n · minSize) | O(n · minSize) |
| Sliding window with letter counts | O(n · minSize) for slicing and hashing windows, O(n) for the window bookkeeping | O(n · minSize) |
Solution code
Try the practice editor first. Both solutions pass every test above.
Maximum Number of Occurrences of a Substring solution in Python
def max_freq(s: str, max_letters: int, min_size: int, max_size: int) -> int:
# A longer qualifying substring always has a qualifying prefix of length
# min_size that occurs at least as often, so max_size never matters.
letters = Counter()
tally = Counter()
for right, ch in enumerate(s):
letters[ch] += 1
left = right - min_size
if left >= 0:
letters[s[left]] -= 1
if letters[s[left]] == 0:
del letters[s[left]]
if right >= min_size - 1 and len(letters) <= max_letters:
tally[s[right - min_size + 1 : right + 1]] += 1
return max(tally.values(), default=0)Maximum Number of Occurrences of a Substring solution in JavaScript
function maxFreq(s, maxLetters, minSize, maxSize) {
// A longer qualifying substring always has a qualifying prefix of length
// minSize that occurs at least as often, so maxSize never matters.
const letters = new Array(26).fill(0);
let distinct = 0;
const tally = new Map();
let best = 0;
for (let right = 0; right < s.length; right++) {
if (letters[s.charCodeAt(right) - 97]++ === 0) distinct++;
const left = right - minSize;
if (left >= 0 && --letters[s.charCodeAt(left) - 97] === 0) distinct--;
if (right >= minSize - 1 && distinct <= maxLetters) {
const sub = s.slice(right - minSize + 1, right + 1);
const c = (tally.get(sub) || 0) + 1;
tally.set(sub, c);
if (c > best) best = c;
}
}
return best;
}Common mistakes
- Looping over every length up to `maxSize`, which is wasted work once you see that shorter substrings always do at least as well.
- Counting only non-overlapping occurrences. Every start index counts.
- Tallying windows before they reach full length, which counts short prefixes at the start of the string.
- Returning 1 when nothing qualifies. If no window passes the distinct-letter check, the answer is 0.
What interviewers look for
The interviewer is mostly listening for the maxSize argument. State it as a short proof: "any qualifying longer substring has a qualifying prefix of length minSize that occurs at least as many times." Saying that crisply matters more than the code.
Then describe the sliding window and say how you track distinct letters in O(1) per step. If asked about hashing cost, mention that substrings of length minSize are at most 26 characters, or that a rolling hash removes the slicing cost entirely.
Follow-up questions
How would you avoid building a substring for every window?
Use a rolling hash (Rabin-Karp) of the window and count hashes instead of strings. Each step updates the hash in O(1), making the whole pass O(n). To rule out collisions, use two moduli or verify candidates at the end.
Why does the shorter-is-better argument still hold with the distinct-letter rule?
Removing characters from the end of a substring can only keep or reduce its number of distinct letters, so the prefix still satisfies `maxLetters`. And the prefix appears at every position the longer string does, plus possibly more.
What if you had to return the substring itself, not just the count?
Keep the tally map and return a key with the highest count, adding a tie-break rule such as the lexicographically smallest or earliest-appearing substring.
Companies that ask Maximum Number of Occurrences of a Substring
Maximum Number of Occurrences of a Substring is tagged by 90 companies in our interview dataset. The score shows how often it comes up at each company.
- Moderna100%
- Optym100%
- CockroachDB100%
- Red Hat96%
- Palantir96%
- Fivetran96%
- Fdm Group93%
- Aveva88%
- Tata Consultancy Services87%
- Xero83%
- Tanla80%
- Bosch Global80%
- Chegg80%
- Ticketmaster79%
- Blizzard Entertainment79%
- Naver75%
- Integral Ad Science75%
- Front73%
- Couchbase70%
- HubSpot69.7%
- Checkr69%
- Lululemon68%
- Pandora67%
- Best Buy67%
and 66 more.
Practice next
Get live help in the real interview
Working solutions in real time during your actual interview. Invisible to screensharing.
Start Free TrialNo credit card required