Browse curriculum

Number of Substrings Containing All Three Characters

Count the substrings of a string of a, b and c that contain at least one of each letter, with a sliding window that counts all right-hand extensions at once.

Problem Understanding

Number of Substrings Containing All Three Characters: given a string s of the letters a, b and c, return how many substrings contain at least one occurrence of each.

Examples: "abcabc" → 10; "aaacb" → 3; "abc" → 1.

The Intuition: A Valid Window Stays Valid to the Right

Containing all three letters is monotone: a longer string that includes a valid one is valid too. So instead of checking every substring:

  1. Grow the sliding window until it holds a, b and c.
  2. Count every substring starting at left that ends at right or later: n − right of them.
  3. Shrink from the left and repeat while still valid.

The window with letter counts is the same as in Minimum Window Substring, and counting many substrings per step echoes Count Number of Nice Subarrays.

Interactive Walkthrough

AMBER = MORE END POINTS, EACH ONE MORE SUBSTRING

EMPTY WINDOW

a

0

b

1

c

2

a

3

b

4

c

5

a

:

b

:

c

:

total

0

 

Count substrings of "abcabc" with at least one a, b and c

Next

Add s[0] = 'a': a 1, b 0, c 0

Free preview: the first 4 of 12 steps

s

On each count step the window with all three letters is filled and the cells after it are marked: each marked cell is one more end point. Try Early to see one step count three substrings.

Dry Run Table

Input: "abcabc", n = 6.

Window Added (n − right) Total
s[0..2] = abc 6 − 2 = 4 4
s[1..3] = bca 6 − 3 = 3 7
s[2..4] = cab 6 − 4 = 2 9
s[3..5] = abc 6 − 5 = 1 10

Answer: 10.

The Solution Template

Three counters and a shrinking window.

Number of Substrings Containing All Three Characters Code
1var numberOfSubstrings = function(s) {
2 const count = [0, 0, 0];
3 let left = 0, total = 0;
4 const n = s.length;
5 for (let right = 0; right < n; right++) {
6 count[s.charCodeAt(right) - 97]++;
7 while (count[0] && count[1] && count[2]) {
8 total += n - right;
9 count[s.charCodeAt(left++) - 97]--;
10 }
11 }
12 return total;
13};

Edge Cases & Common Mistakes

  • Adding 1 instead of n − right: counts only the shortest valid substring per start.
  • A letter missing entirely: the window never becomes valid; the answer is 0.
  • Overflow: with n up to 5 × 10⁴ the total stays below 2³¹, but use 64-bit if you generalize.
  • Using if instead of while: misses starts that are still valid after one shrink.
  • Brute force: O(n²) substrings is too slow for n = 5 × 10⁴.

Summary

Grow the window; while it contains a, b and c, add n − right and shrink from the left. O(n) time, O(1) space.

More practice: DSA interview questions with answers · patterns cheat sheet

The approach, step by step

  1. Grow

    Add s[right] to the letter counts.

  2. Count extensions

    While all three counts are positive, add n - right to the total and remove s[left] from the window.

  3. Return

    After the last character, return the total.

Frequently asked questions

Why add n - right at once?

If s[left..right] already has an a, a b and a c, adding more characters on the right cannot remove them. So the substrings starting at left and ending at right, right + 1, …, n - 1 all qualify: n - right of them, counted in one step.


Why move left inside the while loop?

After counting the substrings that start at left, the next candidate start is left + 1. If the window still has all three letters, those substrings qualify too, so the loop counts them and moves on, until a letter is missing and the window must grow again.


Is there a version without a window?

Yes. Track the last index where each of a, b and c appeared. At each right, every start up to min(last_a, last_b, last_c) gives a valid substring ending at right, so add min(...) + 1. It is also O(n) and O(1).


Can I count 'exactly' with atMost instead?

Not needed here: 'contains all three' is already monotone (adding characters never breaks it), so counting extensions directly is simpler than the atMost difference used in Binary Subarrays With Sum.

New to the technique behind this problem? Watch it run step by step:

Sliding Window Visualization

Applying for software engineering roles? Free, no sign-up:

AI resume checker: match your resume to the job description