📜  使二进制字符串“ab”免费的操作计数(1)

📅  最后修改于: 2023-12-03 15:36:25.820000             🧑  作者: Mango

使二进制字符串 "ab" 免费的操作计数

二进制字符串是由 '0' 和 '1' 组成的字符串。现在我们考虑一种操作,即将 "ab" 转换为 "ba",该操作可以执行任意次数。现在问题是,给定一个二进制字符串,找到使其"ab" 免费的操作计数。

解题思路

由于操作 "ab" 转换为 "ba" 可以无限制地执行,我们可以考虑从左到右依次统计连续出现的 "a" 和 "b" 的个数。我们令 $a[i]$ 表示以第 $i$ 位结尾的连续 "a" 的个数, 令 $b[i]$ 表示以第 $i$ 位结尾的连续 "b" 的个数。那么, 对于第 $i$ 位,如果 $s[i]$ 是 "a",则 $a[i] = a[i-1] + 1$, 否则 $a[i]=0$。同理,如果 $s[i]$ 是 "b",则 $b[i]=b[i-1]+1$,否则 $b[i]=0$。

接下来我们可以分析字符串中出现的 "ab" 的情况:

  1. 如果在第 $i$ 位结尾的连续 "a" 中,存在长度不小于2 的子串,它们之间的 "b" 操作不能免费,此时要先操作将 "ab" 转换为 "ba",再进行后面的操作。操作次数即为子串的个数。
  2. 如果在第 $i$ 位结尾的连续 "a" 后面有连续的 "b",那么这些 "b" 的操作都是免费的,不需要操作任何次数。假设这部分的长度为 $k$,那么最终的操作次数加上 $k$。
  3. 对于连续的 "b",它们之间的操作也是免费的。我们令 $len$ 表示当前连续的 "b" 的长度, $cnt$ 表示已经操作了多少次。如果添加一个 "a",则需要将接下来的 $len$ 个 "b" 转换为 "ba",此时操作次数增加 $cnt + \lfloor len/2 \rfloor$,并将 $len$ 重置为 0, $cnt$ 加上 $\lfloor len/2 \rfloor$。否则,我们继续考虑下一个 "b"。
代码实现
def minOps(s: str) -> int:
    n = len(s)
    a, b = [0]*n, [0]*n
    for i in range(1, n):
        if s[i] == 'a': a[i] = a[i-1] + 1
        if s[i] == 'b': b[i] = b[i-1] + 1

    ans, cnt, len = 0, 0, 0
    for i in range(n):
        if a[i] >= 2:
            ans += a[i]//2
            a[i] %= 2
            b[i] = 0
        if a[i] == 1 and b[i] > 0:
            ans += 1
            b[i] -= 1
            cnt += 1
        if b[i] > 0:
            len += b[i]
            b[i] = 0
            if len >= 2:
                ans += cnt + len//2
                cnt += len//2
                len %= 2
        else:
            cnt = 0
            len = 0

    return ans
测试样例
>>> minOps('abb')
0
>>> minOps('abbb')
1
>>> minOps('abba')
2
>>> minOps('aaabbbaaaabbbbaabb')
9