平衡子串是字符串处理中一个经典问题变种,题目要求我们在一串由'0'和'1'组成的二进制字符串中,找出最长的平衡子串。这里的平衡子串定义为:子串中'0'和'1'的数量相等,且所有'0'都出现在所有'1'之前。
举个实际例子,在字符串"001011"中:
这个问题看似简单,但考察了多个编程基础能力:
最直观的解法是检查所有可能的子串,判断其是否满足平衡条件。具体步骤:
python复制def findTheLongestBalancedSubstring(s):
max_len = 0
n = len(s)
for i in range(n):
for j in range(i+1, n):
substr = s[i:j+1]
cnt0 = substr.count('0')
cnt1 = substr.count('1')
if cnt0 == cnt1:
last0 = substr.rfind('0')
first1 = substr.find('1')
if last0 < first1:
max_len = max(max_len, j-i+1)
return max_len
时间复杂度:O(n³)(双重循环+子串操作)
空间复杂度:O(1)
提示:在LeetCode等编程竞赛中,n的规模通常在10^5级别,这种解法会超时。
观察到平衡子串必须形如"00...0011...11",我们可以改进遍历方式:
python复制def findTheLongestBalancedSubstring(s):
max_len = 0
zeros = ones = 0
for i in range(len(s)):
if s[i] == '0':
if ones != 0: # 遇到新的0段,重置计数
zeros = ones = 0
zeros += 1
else:
ones += 1
max_len = max(max_len, 2 * min(zeros, ones))
return max_len
时间复杂度:O(n)(单次遍历)
空间复杂度:O(1)
算法的核心在于正确处理状态转移:
当前字符为'0'时:
当前字符为'1'时:
几个容易出错的边界情况:
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 暴力枚举 | O(n³) | O(1) | 教学理解,小规模n |
| 滑动窗口优化 | O(n) | O(1) | 竞赛、大规模数据 |
| 前缀和+哈希表 | O(n) | O(n) | 更复杂的平衡条件 |
错误示例:
python复制if s[i] == '0' and s[i-1] == '1': # 错误!可能i=0时越界
zeros = ones = 0
正确做法应使用ones计数器判断:
python复制if s[i] == '0' and ones != 0:
zeros = ones = 0
错误示例:
python复制max_len = max(max_len, 2 * min(zeros, ones)) # 放在循环末尾
这样会在处理'0'时也计算,导致错误。
正确做法应仅在处理'1'时计算:
python复制if s[i] == '1':
ones += 1
max_len = max(max_len, 2 * min(zeros, ones))
错误示例:
python复制zeros = ones = 1 # 错误初始化
正确应为:
python复制zeros = ones = 0 # 从0开始计数
如果题目改为只要求0和1数量相等,不限制顺序,解法会不同:
python复制def balancedSubstring(s):
prefix = {0: -1}
balance = max_len = 0
for i, ch in enumerate(s):
balance += 1 if ch == '1' else -1
if balance in prefix:
max_len = max(max_len, i - prefix[balance])
else:
prefix[balance] = i
return max_len
如果字符集扩大(如包含a,b,c...),要求所有字符出现次数相同:
每个字符有权重,要求各字符权重和相等:
测试用例设计:应包含以下典型情况:
调试技巧:
python复制print(f"i={i}, s[i]={s[i]}, zeros={zeros}, ones={ones}")
性能优化:
编码风格建议:
这类字符串平衡问题在实际中有多种应用:
例如在电商场景中,可以分析用户的"浏览-购买"行为序列,寻找平衡模式:
推荐练习题:
延伸算法学习:
参考书籍:
在解决这类问题时,最重要的是培养分解问题的能力——将复杂问题拆解为可处理的子问题,然后逐步优化解决方案。这道平衡子串问题虽然表面简单,但包含了算法设计的核心思想。