今天在LeetCode第471场周赛中遇到了第二题"3713. 最长的平衡子串 I",这是一道典型的字符串处理问题。题目要求我们找出给定二进制字符串中最长的平衡子串,其中平衡子串定义为包含相同数量的0和1,并且所有0都在1之前的子串。
举个例子,对于字符串"001011",最长的平衡子串是"0011",长度为4。而"0101"虽然0和1数量相同,但不满足0都在1之前的条件,所以不是平衡子串。
最直观的想法是暴力枚举所有可能的子串,然后检查每个子串是否满足平衡条件。对于一个长度为n的字符串,子串数量是O(n²)级别,检查每个子串需要O(n)时间,总时间复杂度为O(n³)。这在n≤50的数据范围内是可行的,因为50³=125,000次操作在现代计算机上可以瞬间完成。
虽然暴力解法可行,但我们可以思考更高效的解法。观察到平衡子串必须满足:
这意味着我们可以寻找这样的区间:在这个区间内,前半部分全是0,后半部分全是1,且0和1的数量相同。这提示我们可以通过统计0和1的累积数量来优化计算。
我们可以使用滑动窗口技术来优化解法。具体步骤如下:
这种方法可以将时间复杂度优化到O(n²),因为每个子串的检查可以在O(1)时间内完成(通过预处理前缀和)。
python复制def findTheLongestBalancedSubstring(s: str) -> int:
max_len = 0
n = len(s)
for i in range(n):
zeros = 0
ones = 0
for j in range(i, n):
if s[j] == '0':
if ones > 0: # 0出现在1之后,不符合条件
break
zeros += 1
else:
ones += 1
if zeros == ones:
max_len = max(max_len, j - i + 1)
return max_len
我们可以预先计算每个位置之前0的数量和之后1的数量,这样可以在O(1)时间内判断任意子串是否平衡。预处理需要O(n)时间,之后每个子串的判断也是O(1),总时间复杂度仍为O(n²),但实际运行效率会更高。
实际上这个问题存在O(n)的解法。我们可以遍历字符串,记录连续的0和1的块。例如,对于字符串"00011101",我们可以将其分解为[(0,3),(1,3),(0,1),(1,1)]。然后比较相邻的0块和1块,取两者较小的数量乘以2作为可能的平衡子串长度。
这种解法只需要一次遍历,时间复杂度为O(n),空间复杂度为O(1)。
python复制test_cases = [
("", 0),
("0", 0),
("1", 0),
("01", 2),
("10", 0),
("0011", 4),
("001011", 4),
("000111", 6),
("000111000", 6),
("0101", 0),
("000000", 0),
("111111", 0)
]
掌握这个问题后,可以尝试解决以下类似题目:
在编程竞赛中遇到这类字符串问题时:
这道题的关键在于理解平衡子串的定义,并能够高效地验证一个子串是否满足条件。通过这次解题,我对滑动窗口技术和字符串处理有了更深的理解。在实际编码时,特别注意边界条件的处理,这往往是出错的高发区。