这里讲解一种general的方法,如果我们给定了一个数组arr,然后在可以相邻的可以进行交换的情况下,变成另一个给定的数组,最小操作次数是多少。

对于本题就是

我们可以按照的元素值对应的顺序,给数组换成对应的索引值,问题就会转变为求逆序对的数量。逆序对可以分治或者树状数组求解,树状数组写比较简单,这里采用树状数组写法。 这里举两个例子:

对于样例1: 
	 arr = 11100
	 target = 10101
	 target元素对应的索引 0:[1,3] 1:[0,2,4]
	 处理出arr对应的索引 [0,2,4,1,3] ,逆序对就为3,可以自己手算一下。
     
对于样例2: 
	 arr = 01011
	 target = 10101
	 target元素对应的索引 0:[0,2] 1:[1,3,4]
	 处理出arr对应的索引 [1,0,3,2,4],逆序对就为2,可以自己手算一下。

code

import sys
from math import inf

# 输入加速
input = sys.stdin.readline
if __name__ == '__main__':
    s = input().strip()
    n = len(s)
    """树状数组模板"""
    tr = [0] * (n + 1)
    def add(i: int, x: int):
        while i <= n:
            tr[i] += x
            i += i & -i
    def query(i: int) -> int:
        res = 0
        while i:
            res += tr[i]
            i -= i & -i
        return res
    """树状数组模板结束"""
    # 处理出上面所说的arr对应的索引数组。
    def process(t: str):
        lst = [[],[]]
        for i in range(n):
            if t[i] == '0':
                lst[0].append(i)
            else:
                lst[1].append(i)
        idxs = []
        j = k = 0
        for i in range(n):
            if s[i] == '0':
                if j < len(lst[0]):
                    idxs.append(lst[0][j])
                else:
                    break
                j += 1
            else:
                if k < len(lst[1]):
                    idxs.append(lst[1][k])
                else:
                    break
                k += 1
        if len(idxs) == n:
            return idxs
        else:
            return []
    idxs = process("10" * n)
    res = inf
    if idxs:
        cnt = 0
        tot = 0
        for i in idxs:
           cnt += tot - query(i + 1)
           add(i + 1, 1)
           tot += 1
        res = min(res,cnt)
    idxs = process("01" * n)
    tr = [0] * (n + 10)
    if idxs:
        cnt = 0
        tot = 0
        for i in idxs:
           cnt += tot - query(i + 1)
           add(i + 1, 1)
           tot += 1
        res = min(res,cnt)
    print(res)