2609. Find the Longest Balanced Substring of a Binary String
Problem Description
You are given a binary string s
that contains only '0'
and '1'
characters.
A substring is considered balanced if it meets two conditions:
- All zeros (
'0'
) appear before all ones ('1'
) in the substring - The number of zeros equals the number of ones
For example:
"0011"
is balanced (2 zeros, then 2 ones)"000111"
is balanced (3 zeros, then 3 ones)"0101"
is NOT balanced (zeros and ones are mixed)"001"
is NOT balanced (different counts of zeros and ones)""
(empty string) is considered balanced
Your task is to find the length of the longest balanced substring within the given string s
.
The solution uses a brute force approach with time complexity O(n³)
. It checks every possible substring s[i..j]
by:
- Enumeration: Using two nested loops to generate all possible substrings
- Validation: The
check
function verifies if a substring is balanced by:- Counting the number of
'1'
s - Ensuring no
'0'
appears after the first'1'
is encountered - Confirming the total length equals twice the count of
'1'
s (meaning equal zeros and ones)
- Counting the number of
- Tracking: Maintaining the maximum length found among all valid balanced substrings
The algorithm returns the length of the longest balanced substring found, or 0
if no balanced substring exists.
Intuition
When we look at what makes a substring balanced, we notice it must have a very specific structure: consecutive zeros followed by consecutive ones, with equal counts. This means a balanced substring always looks like "00...0011...11"
.
Since we need to find the longest such substring, the natural starting point is to consider every possible substring and check if it's balanced. Why does this make sense? Because the balanced substring could start and end at any position in the string.
The key insight for checking if a substring is balanced comes from understanding what would make it unbalanced:
- If we see a
'0'
after we've already seen a'1'
, the substring is immediately invalid - If the counts don't match, it's invalid
This leads us to the checking strategy: as we scan through a substring, we can count the '1'
s we encounter. If we ever see a '0'
after we've started counting '1'
s (when cnt > 0
), we know the substring violates the "all zeros before ones" rule. At the end, if our count of '1'
s times 2 equals the substring length, we know we have equal zeros and ones.
The brute force approach emerges naturally because:
- We don't know where the longest balanced substring starts or ends
- Each substring needs individual validation since there's no obvious pattern to predict which ones are balanced
- The constraints allow us to check all
O(n²)
substrings without timing out
While more efficient solutions exist (like tracking consecutive runs of '0'
s and '1'
s), the brute force method is the most straightforward way to guarantee we don't miss any potential balanced substring.
Solution Approach
The implementation uses a brute force approach with nested loops to examine all possible substrings.
Main Algorithm Structure:
-
Outer enumeration loop: The solution uses two nested loops to generate all possible substrings:
- The outer loop
for i in range(n)
sets the starting position - The inner loop
for j in range(i + 1, n)
sets the ending position - This generates all substrings
s[i..j]
wherei < j
- The outer loop
-
Validation function
check(i, j)
: For each substring, we verify if it's balanced:- Initialize a counter
cnt = 0
to track the number of'1'
s - Iterate through the substring from position
i
toj
- If we encounter a
'1'
, increment the counter - If we encounter a
'0'
AND we've already seen at least one'1'
(whencnt > 0
), immediately returnFalse
as this violates the "all zeros before ones" rule - After scanning the entire substring, check if
cnt * 2 == (j - i + 1)
, which ensures equal numbers of zeros and ones
- Initialize a counter
-
Answer tracking:
- Initialize
ans = 0
to store the maximum length found - Whenever we find a valid balanced substring, update
ans = max(ans, j - i + 1)
- The length is calculated as
j - i + 1
since we're using inclusive indices
- Initialize
Key Implementation Details:
- The check function cleverly combines two validations in one pass: it ensures zeros come before ones while simultaneously counting ones
- The expression
elif cnt:
is a shorthand forelif cnt > 0:
, checking if we've started counting ones - The final validation
cnt * 2 == (j - i + 1)
works because if there arecnt
ones and the total length isj - i + 1
, then there must be(j - i + 1) - cnt
zeros. For balance, we needcnt == (j - i + 1) - cnt
, which simplifies tocnt * 2 == (j - i + 1)
Time Complexity: O(n³)
- Two nested loops generate O(n²)
substrings, and each validation takes O(n)
time.
Space Complexity: O(1)
- Only using a few variables for tracking, no additional data structures needed.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the string s = "001011"
.
Step 1: Initialize
n = 6
(length of string)ans = 0
(to track maximum balanced substring length)
Step 2: Enumerate all substrings
We'll check each substring systematically:
i = 0 (starting from index 0):
j = 1
: Check"00"
→ Not balanced (2 zeros, 0 ones)j = 2
: Check"001"
→ Not balanced (2 zeros, 1 one)j = 3
: Check"0010"
→ Not balanced (has '0' after '1')j = 4
: Check"00101"
→ Not balanced (has '0' after '1')j = 5
: Check"001011"
→ Not balanced (has '0' after '1')
i = 1 (starting from index 1):
j = 2
: Check"01"
→ Balanced! (1 zero, 1 one, zeros before ones)- Update
ans = 2
- Update
j = 3
: Check"010"
→ Not balanced (has '0' after '1')j = 4
: Check"0101"
→ Not balanced (has '0' after '1')j = 5
: Check"01011"
→ Not balanced (has '0' after '1')
i = 2 (starting from index 2):
j = 3
: Check"10"
→ Not balanced (1 one, 1 zero, but zero comes after one)j = 4
: Check"101"
→ Not balanced (has '0' after '1')j = 5
: Check"1011"
→ Not balanced (has '0' after '1')
i = 3 (starting from index 3):
j = 4
: Check"01"
→ Balanced! (1 zero, 1 one, zeros before ones)ans
remains 2 (not larger than current max)
j = 5
: Check"011"
→ Not balanced (1 zero, 2 ones)
i = 4 (starting from index 4):
j = 5
: Check"11"
→ Not balanced (0 zeros, 2 ones)
Step 3: Return result
The longest balanced substring has length 2
(either "01"
at indices [1,2] or [3,4]).
How the check function works for "01"
(indices 1 to 2):
- Start with
cnt = 0
- At index 1: see '0',
cnt
is still 0, continue - At index 2: see '1', increment
cnt
to 1 - Final check:
cnt * 2 = 1 * 2 = 2
, substring length =2 - 1 + 1 = 2
- Since
2 == 2
, returnTrue
(balanced!)
How the check function works for "010"
(indices 1 to 3):
- Start with
cnt = 0
- At index 1: see '0',
cnt
is still 0, continue - At index 2: see '1', increment
cnt
to 1 - At index 3: see '0', but
cnt > 0
(we've seen a '1'), returnFalse
immediately
Solution Implementation
1class Solution:
2 def findTheLongestBalancedSubstring(self, s: str) -> int:
3 """
4 Find the length of the longest balanced substring in s.
5 A balanced substring has all 0s before all 1s with equal counts.
6
7 Args:
8 s: A binary string containing only '0' and '1'
9
10 Returns:
11 The length of the longest balanced substring
12 """
13
14 def is_balanced_substring(start_idx: int, end_idx: int) -> bool:
15 """
16 Check if substring s[start_idx:end_idx+1] is balanced.
17 A balanced substring must have:
18 1. All zeros come before all ones
19 2. Equal number of zeros and ones
20
21 Args:
22 start_idx: Starting index of substring (inclusive)
23 end_idx: Ending index of substring (inclusive)
24
25 Returns:
26 True if the substring is balanced, False otherwise
27 """
28 ones_count = 0
29
30 # Iterate through the substring
31 for idx in range(start_idx, end_idx + 1):
32 if s[idx] == '1':
33 ones_count += 1
34 elif ones_count > 0:
35 # Found a '0' after seeing at least one '1'
36 # This violates the balanced property
37 return False
38
39 # Check if number of 1s equals half the substring length
40 # (which means equal 0s and 1s)
41 substring_length = end_idx - start_idx + 1
42 return ones_count * 2 == substring_length
43
44 string_length = len(s)
45 max_balanced_length = 0
46
47 # Try all possible substrings
48 for start in range(string_length):
49 for end in range(start + 1, string_length):
50 if is_balanced_substring(start, end):
51 current_length = end - start + 1
52 max_balanced_length = max(max_balanced_length, current_length)
53
54 return max_balanced_length
55
1class Solution {
2 /**
3 * Finds the length of the longest balanced substring in the given string.
4 * A balanced substring has equal number of '0's followed by equal number of '1's.
5 *
6 * @param s The input string containing only '0's and '1's
7 * @return The length of the longest balanced substring
8 */
9 public int findTheLongestBalancedSubstring(String s) {
10 int stringLength = s.length();
11 int maxBalancedLength = 0;
12
13 // Try all possible starting positions
14 for (int startIndex = 0; startIndex < stringLength; ++startIndex) {
15 // Try all possible ending positions after the start
16 for (int endIndex = startIndex + 1; endIndex < stringLength; ++endIndex) {
17 // Check if substring from startIndex to endIndex is balanced
18 if (isBalancedSubstring(s, startIndex, endIndex)) {
19 // Update maximum length if current substring is longer
20 int currentLength = endIndex - startIndex + 1;
21 maxBalancedLength = Math.max(maxBalancedLength, currentLength);
22 }
23 }
24 }
25
26 return maxBalancedLength;
27 }
28
29 /**
30 * Checks if the substring from index i to j (inclusive) is balanced.
31 * A balanced substring must have all '0's before all '1's and equal counts.
32 *
33 * @param s The input string
34 * @param startIndex The starting index of the substring (inclusive)
35 * @param endIndex The ending index of the substring (inclusive)
36 * @return true if the substring is balanced, false otherwise
37 */
38 private boolean isBalancedSubstring(String s, int startIndex, int endIndex) {
39 int onesCount = 0;
40
41 // Iterate through the substring
42 for (int currentIndex = startIndex; currentIndex <= endIndex; ++currentIndex) {
43 if (s.charAt(currentIndex) == '1') {
44 // Count the number of '1's
45 ++onesCount;
46 } else if (onesCount > 0) {
47 // If we encounter a '0' after seeing a '1', it's not balanced
48 return false;
49 }
50 }
51
52 // Check if number of '1's equals number of '0's
53 // Total length = endIndex - startIndex + 1
54 // For balanced: onesCount should equal zerosCount, so onesCount * 2 = total length
55 return onesCount * 2 == endIndex - startIndex + 1;
56 }
57}
58
1class Solution {
2public:
3 int findTheLongestBalancedSubstring(string s) {
4 int stringLength = s.size();
5 int maxBalancedLength = 0;
6
7 // Lambda function to check if substring from index start to end is balanced
8 // A balanced substring has format: 0...0 1...1 where count of 0s equals count of 1s
9 auto isBalancedSubstring = [&](int start, int end) -> bool {
10 int onesCount = 0;
11
12 // Traverse the substring
13 for (int index = start; index <= end; ++index) {
14 if (s[index] == '1') {
15 // Count the 1s
16 ++onesCount;
17 } else if (onesCount > 0) {
18 // If we encounter a 0 after seeing 1s, it's not balanced
19 return false;
20 }
21 }
22
23 // Check if the number of 1s equals half the substring length
24 // This ensures equal number of 0s and 1s
25 return onesCount * 2 == end - start + 1;
26 };
27
28 // Try all possible substrings
29 for (int startIndex = 0; startIndex < stringLength; ++startIndex) {
30 for (int endIndex = startIndex + 1; endIndex < stringLength; ++endIndex) {
31 // Check if current substring is balanced
32 if (isBalancedSubstring(startIndex, endIndex)) {
33 // Update maximum balanced length found
34 maxBalancedLength = max(maxBalancedLength, endIndex - startIndex + 1);
35 }
36 }
37 }
38
39 return maxBalancedLength;
40 }
41};
42
1/**
2 * Finds the length of the longest balanced substring in a binary string.
3 * A balanced substring has equal number of 0s and 1s, with all 0s appearing before all 1s.
4 *
5 * @param s - The input binary string containing only '0' and '1' characters
6 * @returns The length of the longest balanced substring
7 */
8function findTheLongestBalancedSubstring(s: string): number {
9 const stringLength: number = s.length;
10 let maxBalancedLength: number = 0;
11
12 /**
13 * Checks if the substring from index startIndex to endIndex (inclusive) is balanced.
14 * A substring is balanced if:
15 * 1. It contains equal number of 0s and 1s
16 * 2. All 0s appear before all 1s (no 0s after the first 1)
17 *
18 * @param startIndex - Starting index of the substring
19 * @param endIndex - Ending index of the substring (inclusive)
20 * @returns True if the substring is balanced, false otherwise
21 */
22 const isBalancedSubstring = (startIndex: number, endIndex: number): boolean => {
23 let onesCount: number = 0;
24
25 // Iterate through the substring
26 for (let currentIndex: number = startIndex; currentIndex <= endIndex; ++currentIndex) {
27 if (s[currentIndex] === '1') {
28 // Count the number of 1s
29 ++onesCount;
30 } else if (onesCount > 0) {
31 // Found a 0 after encountering a 1, not balanced
32 return false;
33 }
34 }
35
36 // Check if number of 1s equals number of 0s (half of total length)
37 const substringLength: number = endIndex - startIndex + 1;
38 return onesCount * 2 === substringLength;
39 };
40
41 // Try all possible substrings with even length
42 for (let startIndex: number = 0; startIndex < stringLength; ++startIndex) {
43 // Only check substrings with even length (increment by 2)
44 for (let endIndex: number = startIndex + 1; endIndex < stringLength; endIndex += 2) {
45 if (isBalancedSubstring(startIndex, endIndex)) {
46 // Update maximum balanced length if current substring is longer
47 maxBalancedLength = Math.max(maxBalancedLength, endIndex - startIndex + 1);
48 }
49 }
50 }
51
52 return maxBalancedLength;
53}
54
Time and Space Complexity
The time complexity of this code is O(n³)
, where n
is the length of string s
.
This is because:
- The outer loop starting at line 13 iterates through all possible starting positions
i
, which runsn
times - The inner loop at line 14 iterates through all possible ending positions
j
fromi+1
ton-1
, which runs up ton-1
times in the worst case - For each pair
(i, j)
, thecheck
function is called, which iterates fromi
toj
(line 5), taking up ton
operations in the worst case - Therefore, the total time complexity is
O(n) × O(n) × O(n) = O(n³)
The space complexity is O(1)
as the algorithm only uses a constant amount of extra space:
- The
check
function uses a single integer variablecnt
to count occurrences - The main function uses variables
n
andans
to store the length and result - No additional data structures that grow with input size are used
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Off-by-One Error in Substring Length Calculation
A common mistake is incorrectly calculating the substring length or using the wrong loop boundaries. Many developers accidentally write:
Incorrect:
for end in range(start + 1, string_length):
if is_balanced_substring(start, end):
current_length = end - start # Wrong! Missing +1
Correct:
for end in range(start + 1, string_length):
if is_balanced_substring(start, end):
current_length = end - start + 1 # Correct: inclusive indices
2. Incorrect Loop Range Leading to Missing Substrings
Another pitfall is using range(start, string_length)
for the end index, which would miss single-character positions and create confusion with inclusive/exclusive boundaries:
Incorrect:
for start in range(string_length):
for end in range(start, string_length): # Wrong! Includes start==end
if is_balanced_substring(start, end):
# This would check single characters and empty substrings
Correct:
for start in range(string_length):
for end in range(start + 1, string_length): # Ensures end > start
if is_balanced_substring(start, end):
# Properly checks substrings of length 2 or more
3. Forgetting Edge Cases for Empty or Odd-Length Substrings
Since balanced substrings must have equal zeros and ones, they must have even length. Checking odd-length substrings wastes computation:
Optimized Solution:
for start in range(string_length):
# Start from start+1 and increment by 2 for even-length substrings only
for end in range(start + 1, string_length, 2):
if is_balanced_substring(start, end):
current_length = end - start + 1
max_balanced_length = max(max_balanced_length, current_length)
4. Inefficient Validation Logic
Some implementations might check the balanced property inefficiently by first counting all zeros and ones, then checking their positions:
Inefficient:
def is_balanced_substring(start, end):
substring = s[start:end+1]
zeros = substring.count('0')
ones = substring.count('1')
if zeros != ones:
return False
# Then check if all zeros come before ones
first_one_idx = substring.find('1')
if first_one_idx != -1:
return '0' not in substring[first_one_idx:]
return True
The original solution's approach is better as it combines both checks in a single pass, immediately returning False
when finding a '0' after a '1'.
Which algorithm is best for finding the shortest distance between two points in an unweighted graph?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!