AlgoMaster Logo

Count Binary Substrings

Last Updated: March 31, 2026

easy

Understanding the Problem

We need to count substrings where all 0's are grouped together and all 1's are grouped together, and both groups have the same size. So "0011" counts (two 0's followed by two 1's), "01" counts, "10" counts, "1100" counts. But "0101" does not count because the 0's and 1's are interleaved, not grouped.

The key observation is that valid substrings always occur at the boundary between a group of one character and a group of the other. If you have a group of three 0's followed by a group of two 1's ("00011"), the valid substrings that span this boundary are "01" and "0011". That's 2 substrings, which is the minimum of the two group sizes (min(3, 2) = 2). This pattern holds for every adjacent pair of groups in the string.

So the problem reduces to: group consecutive identical characters, then for each pair of adjacent groups, add the minimum of their sizes to the answer.

Key Constraints:

  • 1 <= s.length <= 10^5 — With n up to 100,000, we need an O(n) or O(n log n) solution. An O(n^2) brute force that checks every substring will hit 10 billion operations in the worst case, which is too slow.
  • s[i] is either '0' or '1' — This is a binary string. There are only two possible characters, so groups naturally alternate between 0-groups and 1-groups.

Approach 1: Brute Force

Intuition

The most direct approach: check every possible substring to see if it's valid. A valid substring has all its 0's grouped together, all its 1's grouped together, and equal counts of both.

For any substring, we can check validity by verifying it looks like "000...111..." or "111...000..." with equal halves. Since valid substrings always have even length (equal 0's and 1's), we only need to check even-length substrings.

Algorithm

  1. Initialize count = 0.
  2. For each starting index i from 0 to n - 1:
    • For each even length len from 2 to n - i:
      • Check if the first half is all one character and the second half is all the other character.
      • If valid, increment count. Otherwise, break (longer substrings from here won't be valid either).
  3. Return count.

Example Walkthrough

1Check all even-length substrings starting at each index
0
0
i
1
0
2
1
3
1
1/6

Code

If we know there's a group of five 0's followed by three 1's, that tells us there are 3 valid substrings at that boundary. We don't need to check each one by scanning characters.

What if we counted the size of each consecutive group and used adjacent group sizes to compute the answer directly?

Approach 2: Group Counting

Intuition

Instead of checking every substring, let's think about the structure of the string differently. A binary string is just a sequence of groups: a run of 0's, then a run of 1's, then a run of 0's, and so on. For example, "00110011" has groups of sizes [2, 2, 2, 2].

Valid substrings always span exactly two adjacent groups. If one group has size a and the next has size b, the number of valid substrings crossing that boundary is min(a, b). You can form substrings of length 2, 4, 6, ... up to 2 * min(a, b) by taking equal portions from each group.

Algorithm

  1. Walk through the string and compute the sizes of consecutive groups. Store them in an array.
  2. For each pair of adjacent groups, add min(groups[i], groups[i+1]) to the result.
  3. Return the result.

Example Walkthrough

1Start: scan string to build group sizes
0
0
i
1
0
2
1
3
1
4
0
5
0
6
1
7
1
1/6

Code

This approach is O(n) time but uses O(n) extra space. We only ever compare two adjacent groups at a time, so storing all groups is unnecessary.

What if we tracked just two values, the previous and current group sizes, and accumulated the result on the fly?

Approach 3: Optimized Single Pass (Two Counters)

Intuition

We can compress Approach 2 into a single pass without storing all group sizes. Maintain two variables: prevGroupSize (the size of the previous group) and currGroupSize (the size of the group we're currently building). Every time we transition from one character to another, the current group becomes the previous group, and we start a new current group.

At each character, if prevGroupSize >= currGroupSize, we can form one more valid substring at this boundary, so we increment the count.

Algorithm

  1. Initialize prevGroupSize = 0, currGroupSize = 1, and count = 0.
  2. Iterate from index 1 to n - 1:
    • If s[i] == s[i - 1], the current group extends: increment currGroupSize.
    • Otherwise, a new group starts: set prevGroupSize = currGroupSize and reset currGroupSize = 1.
    • If prevGroupSize >= currGroupSize, increment count.
  3. Return count.

Example Walkthrough

1Init: prev=0, curr=1, count=0. Start at i=1
0
0
curr grp
1
0
i
2
1
3
1
4
0
5
0
6
1
7
1
1/9

Code