📌  相关文章
📜  将二进制字符串转换为另一个所需的最小子字符串翻转次数(1)

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

将二进制字符串转换为另一个所需的最小子字符串翻转次数

介绍

给定两个长度相等的二进制字符串s和t,将s中的子串翻转后,可以得到新的字符串s'。现在要求将s'转换为t,求最小的翻转次数。

例如,s = "1100",t = "1110",在将s中的子串"100"翻转后,可以得到s' = "1110",此时已满足条件,所以最小的翻转次数为1。

本题考察字符串操作和贪心算法的实现。

算法思路
  1. 首先对s和t进行遍历,对于s[i]和t[i]不相等的位置,记录需要翻转的子串的开始和结束位置idx1和idx2,并且将需要翻转的子串添加到数组flip中。

  2. 对于flip中的每一个子串,如果子串的长度为奇数,则中间那个字符必然要翻转,所以可以将翻转次数减一。

  3. 对于flip数组中相邻的两个子串,如果第一个子串的结束位置等于第二个子串的开始位置,则可以将这两个子串合并为一个子串,这样可以减少翻转次数。如下图所示:

    flip.png

    可以看出,将flip数组中的两个子串合并后,从第一个子串的开始位置到第二个子串的结束位置中间的一段子串就不用再翻转了,所以要将翻转次数减二。

  4. 最终的翻转次数即为flip数组中的子串数量。

代码实现
def min_flip(s: str, t: str) -> int:
    n = len(s)
    flip = []
    idx1, idx2 = -1, -1

    for i in range(n):
        if s[i] != t[i]:
            if idx1 == -1:
                idx1 = i
            idx2 = i
        else:
            if idx1 != -1:
                flip.append((idx1, idx2))
                idx1, idx2 = -1, -1
    if idx1 != -1:
        flip.append((idx1, idx2))
    
    res = 0
    for i in range(len(flip)):
        l, r = flip[i]
        if (r - l + 1) % 2 == 1:
            res += 1
        if i < len(flip) - 1 and flip[i + 1][0] == r + 1:
            res -= 2
    return max(0, res)
总结

本题中需要注意的是,如果翻转的子串中存在奇数个字符,那么中间那个字符必须翻转,这一点需要格外注意。另外,将相邻的两个子串合并时,要将翻转次数减二而不是减一。