Given a string s consisting only of the characters a, b, and c, return the number of substrings that contain at least one occurrence of each of a, b, and c.
<= left is valid, so add left to the total, shrinking to keep the invariant.Input: s = "abcabc" Output: 10 There are 10 substrings that contain at least one a, one b, and one c.
Input: s = "aaacb" Output: 3 The valid substrings are "aacb", "acb", and "aaacb".
- 3 <= s.length <= 5 * 10^4 - s consists only of characters a, b and c.
This is a counting problem, so fix the right endpoint and count valid left endpoints. The key fact: a substring ending at index i contains all three characters exactly when it starts at or before the earliest of the three most-recent positions of a, b, c. That gives the count for each i in O(1).
“At least one of each, or exactly one?”
At least one — the substring must contain a, b, and c, in any amounts.
“Are overlapping substrings counted separately?”
Yes — every distinct (start, end) pair that qualifies is counted.
I'll count, for each right endpoint, how many left starts give a valid substring.
A substring ending at i is valid iff it starts at or before the earliest of the last-seen positions of a, b, and c.
So the count for i is min(lastA, lastB, lastC) + 1, and I sum that over all i.
Worked example — s = "abcabc"
i=2 (c): last=(0,1,2) -> min 0 -> +1 total 1 i=3 (a): last=(3,1,2) -> min 1 -> +2 total 3 i=4 (b): last=(3,4,2) -> min 2 -> +3 total 6 i=5 (c): last=(3,4,5) -> min 3 -> +4 total 10 answer: 10
For each right endpoint, the valid start positions form a contiguous prefix 0..min(last), so their number is min(last) + 1 — computable in O(1).
A substring covers all three only back to the earliest of the three last-seen positions; that minimum is the furthest-left start that still includes every character.
You only need the last index of each of a, b, c. No map, no window to shrink — just accumulate min(last) + 1 as you go.
| Extend from each start | Last-seen count | |
|---|---|---|
| Idea | From each start, find the first all-three end, add the rest | Per right, add min(last a,b,c) + 1 |
| Time | O(n^2) | O(n) |
| Space | O(1) | O(1) |
The brute finds, for each start, the first valid end and adds the suffix count; the last-seen method flips it to per-right and reads the count off three integers. Full code is in the Approaches selector below.
Key takeaway
Count per right endpoint: a substring ending at i contains all three characters iff it starts at or before min(last[a], last[b], last[c]), giving min(last) + 1 valid starts. Sum that over all i — one pass, three integers, O(n).
last = [-1, -1, -1]; count = 0
for i, ch in enumerate(s):
last[ch] = i
count += 1 + min(last) # min is -1 until all three are seen
return count