最长平衡子字符串

标签: 字符串

难度: Easy

给你一个仅由 01 组成的二进制字符串 s  

如果子字符串中 所有的 0 都在 1 之前 且其中 0 的数量等于 1 的数量,则认为 s 的这个子字符串是平衡子字符串。请注意,空子字符串也视作平衡子字符串。 

返回  s 中最长的平衡子字符串长度。

子字符串是字符串中的一个连续字符序列。

示例 1:

输入:s = "01000111"
输出:6
解释:最长的平衡子字符串是 "000111" ,长度为 6 。

示例 2:

输入:s = "00111"
输出:4
解释:最长的平衡子字符串是 "0011" ,长度为  4 。

示例 3:

输入:s = "111"
输出:0
解释:除了空子字符串之外不存在其他平衡子字符串,所以答案为 0 。

提示:

  • 1 <= s.length <= 50
  • '0' <= s[i] <= '1'

Submission

运行时间: 30 ms

内存: 16.1 MB

class Solution:
    def findTheLongestBalancedSubstring(self, s: str) -> int:
        flag = True
        num0 = 0
        res = 0
        ans = 0
        for i in s:
            if i == '0' and flag:
                num0 += 1
            elif i == '1' and num0:
                flag = False
                num0 -= 1
                res += 1
                ans = max(ans,2 * res)
            elif i == '0' and not flag:
                flag = True
                num0 = 1
                res = 0
        return ans

Explain

这个题解的思路主要是基于追踪遇到的0和1的数量。初始设定一个标记flag为True表示当前正在统计0的数量。当遇到0且flag为True时,增加0的数量。若遇到1且已有0存在,将flag设置为False表示开始匹配1和之前的0。每成功匹配一对0和1时,减少0的计数并增加已匹配对的计数。若遇到0且flag为False,表示当前0不可能与前面的1匹配,因此重新设置flag为True并重置0的计数与匹配对的计数。通过维护一个最大值ans来记录至今发现的最长平衡子字符串长度。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution:
    def findTheLongestBalancedSubstring(self, s: str) -> int:
        flag = True  # 标记是否正在统计0的数量
        num0 = 0  # 用于统计0的数量
        res = 0  # 当前平衡子字符串中匹配的0和1对的数量
        ans = 0  # 最长的平衡子字符串长度
        for i in s:
            if i == '0' and flag:
                num0 += 1  # 统计0的数量
            elif i == '1' and num0:
                flag = False  # 开始匹配1与之前的0
                num0 -= 1  # 每匹配一个1,0的数量减1
                res += 1  # 匹配成功的对数增加
                ans = max(ans, 2 * res)  # 更新最长平衡子字符串的长度
            elif i == '0' and not flag:
                flag = True  # 遇到新的0,重新统计0的数量
                num0 = 1
                res = 0  # 重置匹配对的计数
        return ans

Explore

在题解的逻辑中,我们维护一个标志`flag`初始设为True,表示当前是在统计0的数量。当遇到'0'并且`flag`为True时,我们会继续增加0的统计数量。当我们遇到'1'时,如果已经统计了一些0(`num0`大于0),则意味着我们有潜在的0可以与此'1'匹配,从而形成平衡的0和1对。因此,此时将`flag`设置为False,开始匹配1与之前的0,而不是继续统计0,这是因为我们需要寻找平衡的子字符串,而单独增加更多的0会破坏已经开始形成的平衡结构。

当`flag`为False且遇到新的'0'时,这表示当前的1数量已经用完(与之前统计的0数量已匹配完成),再遇到0意味着之前形成的平衡区间已经结束。在这种情况下,我们将重新开始统计新的0,因为之前的匹配对已经计入了最长平衡子字符串的长度(通过`ans`变量更新)。此时重置`num0`和`res`并不会遗漏有效的匹配对,因为已匹配的对数已经被考虑过,而无法形成平衡的0或1(如额外的1或开始新的0序列)标志着需要重新开始一个新的可能的平衡区间。

在题解逻辑中,最长平衡子字符串的长度只在找到一个新的匹配对即0和1匹配成功时更新,因为只有这时平衡子字符串的有效长度增加(每成功匹配一对,长度增加2)。遇到单独的0不会直接影响当前平衡子字符串的长度,因为没有相应的1与之匹配形成平衡对。只有在0和1成功匹配时,才能确定增加了平衡子字符串的长度,因此,没有在遇到0时更新是因为这不会增加任何已经存在的平衡子字符串长度。这种方法不会遗漏最大长度的更新,因为每次匹配对成功时都进行了检查和更新。