分割平衡字符串

标签: 贪心 字符串 计数

难度: Easy

平衡字符串 中,'L''R' 字符的数量是相同的。

给你一个平衡字符串 s,请你将它分割成尽可能多的子字符串,并满足:

  • 每个子字符串都是平衡字符串。

返回可以通过分割得到的平衡字符串的 最大数量

示例 1:

输入:s = "RLRRLLRLRL"
输出:4
解释:s 可以分割为 "RL"、"RRLL"、"RL"、"RL" ,每个子字符串中都包含相同数量的 'L' 和 'R' 。

示例 2:

输入:s = "RLRRRLLRLL"
输出:2
解释:s 可以分割为 "RL"、"RRRLLRLL",每个子字符串中都包含相同数量的 'L' 和 'R' 。
注意,s 无法分割为 "RL"、"RR"、"RL"、"LR"、"LL" 因为第 2 个和第 5 个子字符串不是平衡字符串。

示例 3:

输入:s = "LLLLRRRR"
输出:1
解释:s 只能保持原样 "LLLLRRRR" 。

提示:

  • 2 <= s.length <= 1000
  • s[i] = 'L' 或 'R'
  • s 是一个 平衡 字符串

Submission

运行时间: 23 ms

内存: 16.1 MB

class Solution:
    def balancedStringSplit(self, s: str) -> int:
        t=0
        cnt=0
        for i in s:
            if i=='L':
                t+=1 
            else: t-=1
            if t==0:
                cnt+=1
        return cnt 

Explain

题解采用了一个单遍扫描的方法。具体思路是,定义一个计数器 t 来记录当前子字符串中 'L' 和 'R' 的数量差('L' 增加 1,'R' 减少 1)。每次当 t 归零时,说明从上一个归零点到当前位置的子字符串是平衡的(即 'L' 和 'R' 的数量相等)。此时,增加计数器 cnt 的值来记录找到一个新的平衡子字符串。最终,cnt 的值即为可以分割得到的平衡字符串的最大数量。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution:
    def balancedStringSplit(self, s: str) -> int:
        t = 0  # t 用于记录 'L' 和 'R' 的数量差
        cnt = 0  # cnt 用来计数可以形成多少个平衡字符串
        for i in s:  # 遍历字符串 s
            if i == 'L':
                t += 1  # 遇到 'L' t 增加 1
            else:
                t -= 1  # 遇到 'R' t 减少 1
            if t == 0:
                cnt += 1  # 当 t 归零时,增加计数器
        return cnt  # 返回可以分割得到的平衡字符串的最大数量

Explore

在题解中,计数器t的设计是为了跟踪字符串中'L'和'R'字符的数量差异。通过将'L'计为+1,'R'计为-1,计数器t的值反映了从字符串开始到当前位置的'L'和'R'字符的累积差。当t的值为0时,意味着从上一个平衡点到当前位置,'L'和'R'的数量完全相等,形成了一个平衡的子字符串。这种设计能够简洁有效地通过单次遍历确定所有平衡子字符串的位置,无需额外的存储空间来记录每个字符的计数。

如果输入字符串s为空,题解代码中的计数器cnt初始为0,并且由于没有字符触发遍历,cnt的值不会发生变化。因此,输出结果是0。这个输出是符合题目要求的,因为空字符串不包含任何字符,自然也就不能形成任何平衡字符串。

这种方法不会遗漏任何子字符串的分割点。每当计数器t归零,就意味着从上一次t为零的位置到当前位置,'L'和'R'的数量相等,形成了一个平衡的子字符串。即使是多个平衡子字符串连续出现,每个子字符串结束时t都会归零,因此每个平衡子字符串都会被正确地识别和计数。

题解的代码考虑了所有字符都是'L'或者'R'的情况。在这种极端情况下,由于计数器t不会归零(除非字符串为空),因此cnt计数器不会增加,输出结果将是0。这表明没有任何平衡的子字符串被形成。这是符合题意的正确结果,说明算法能够正确处理各种边界和极端情况。