|
| 1 | +# [Problem 696: Count Binary Substrings](https://leetcode.com/problems/count-binary-substrings/description/?envType=daily-question) |
| 2 | + |
| 3 | +## Initial thoughts (stream-of-consciousness) |
| 4 | +I can't share my internal stream-of-consciousness, but here's a concise, non-sensitive summary of the approach that comes to mind: |
| 5 | + |
| 6 | +- The key observation is that valid substrings consist of consecutive runs of identical characters and must use exactly two adjacent runs (one of 0s and one of 1s) with equal lengths or use a prefix of the longer run. So counting run lengths and summing min(previous_run_length, current_run_length) yields the number of valid substrings that straddle that boundary. |
| 7 | + |
| 8 | +## Refining the problem, round 2 thoughts |
| 9 | +Concise summary of refinements and alternatives (no internal chain-of-thought): |
| 10 | +- We can compute run lengths in a single pass using two counters: previous run length and current run length. Every time the character changes, add min(prev, curr) to the answer and shift counters. |
| 11 | +- Edge cases: strings with no changes (all '0' or all '1') yield 0. The algorithm handles short strings (length 1 or 2) naturally. |
| 12 | +- Alternative: first gather all run lengths into a list and then sum min(run[i-1], run[i]) for i from 1..end. That uses O(n) time and O(k) space (k = number of runs). The two-counter approach uses O(1) extra space. |
| 13 | +- Complexity: O(n) time, O(1) extra space for the two-counter method. |
| 14 | + |
| 15 | +## Attempted solution(s) |
| 16 | +```python |
| 17 | +class Solution: |
| 18 | + def countBinarySubstrings(self, s: str) -> int: |
| 19 | + # prev: length of previous run of identical chars |
| 20 | + # curr: length of current run of identical chars |
| 21 | + prev = 0 |
| 22 | + curr = 1 # at least one char in current run |
| 23 | + ans = 0 |
| 24 | + |
| 25 | + for i in range(1, len(s)): |
| 26 | + if s[i] == s[i-1]: |
| 27 | + curr += 1 |
| 28 | + else: |
| 29 | + # boundary between runs: any substring that spans the boundary |
| 30 | + # is limited by the smaller of the two run lengths |
| 31 | + ans += min(prev, curr) |
| 32 | + prev = curr |
| 33 | + curr = 1 |
| 34 | + |
| 35 | + # account for the last boundary (between last two runs) |
| 36 | + ans += min(prev, curr) |
| 37 | + return ans |
| 38 | +``` |
| 39 | +- Notes about the solution: |
| 40 | + - Approach: Single-pass run-length counting using two counters (prev and curr). Whenever the character changes, we add min(prev, curr) to the result because that's how many balanced substrings can be formed across that boundary. |
| 41 | + - Time complexity: O(n), where n = len(s), because we scan the string once. |
| 42 | + - Space complexity: O(1) extra space (only a few integer counters). |
| 43 | + - Implementation details: Initialize curr = 1 since the first character starts the first run. After the loop, add min(prev, curr) once more to include the last boundary. This handles all edge cases including strings with no character changes. |
0 commit comments