文章目录
题目描述
如果一个二进制字符串,是以一些 0(可能没有 0)后面跟着一些 1(也可能没有 1)的形式组成的,那么该字符串是 单调递增 的。
给你一个二进制字符串 s,你可以将任何 0 翻转为 1 或者将 1 翻转为 0 。
返回使 s 单调递增的最小翻转次数。示例 1:
输入:s = “00110”
输出:1
解释:翻转最后一位得到 00111.示例 2:
输入:s = “010110”
输出:2
解释:翻转得到 011111,或者是 000111。示例 3:
输入:s = “00011000”
输出:2
解释:翻转得到 00000000
思路分析
用穷举的方式找到所有的可能,然后在此过程中记录最小操作数。
答案必定是 N个0 +N个1 的组合方式,N可以为0。
比如对于题目示例1所给出的字符串:
s = “00110”
我们可以得到的全部可能:
- 00000 操作2次 (1变成0)
- 00001 操作3次
- 00011 操作2次
- 00111 操作1次
- 01111 操作2次
- 11111 操作3次
可以看到只有将最后的0变成1是最小的操作次数。
我们假设一个记号X,让X不断的从字符串开头移动到字符串末尾,移动的过程中 要将X的前面的1变成0,X后面的0变成1,过程中记录最小的操作次数即可。
比如 当X下标为0的时候 字符串为 X00110 ,X前面没有数字,X后面0有三个,所以操作次数为3。
在这个思路中加入前缀和。 建立一个数组记录X前面需要改变的字符数。
例如 s = “00110” 则前缀和数组为 [0, 0, 0, 1, 2, 2].
这里其实比较好想,当记号X下标为0,1,2,时。s= X00110,s=0X0110,s=00X110
这三个字符串X前面需要改变的字符数都是0(即前面为1的个数)
当X下标为3时,即 s= 001X10 , X前面需要改变的字符数为1,所以前缀和数组下标为3的地方是1,以此类推。
建立前缀和数组的时候要小心,要搞清楚有多少个数,标记点是从0开始到最后一个字符的后面,所以比s长度多一位。
拿到前缀和数组之后,就要计算当前字符的总操作数,就是记号X前面的操作数(有多少1)+X后面的操作数(有多少0)。
X前面的操作数就是前缀和中当前下标的数,而X后面需要操作的数需要计算一下(实际上就是算X后面有多少个0):
- 由 S的长度减去当前的下标 得到 当前标记X后面有多少个字符。
- 前缀和数组的最后一位数记录了字符串s里有多少个1。所以当前下标的前缀和记录了X之前有多少个1,他俩做减法就得到了 当前X之后有多少个1。
- 上面两步做减法,就得到了X后面又多少个0。
说的可能比较乱,来个示例看一下 例如 s = “00110” 则前缀和数组为 temp = [0, 0, 0, 1, 2, 2].
假设此时X的下标为i = 3 即 s= 001X10
计算此时最小操作步骤过程:
- len(s) - i = 2 ,(2就是X后面还有几个字符)
- temp[len(s)] - temp[i] = 1, (从前缀和数组上看,整个字符串有多少个1,当前下标i前面有多少个1.相减即是当前下标i后面有多少个1.)
- (len(s) - i -(temp[len(s)] - temp[i]) = 1 ,(上面两步相减,得到当前记号X后面有多少个0,即X后面需要操作的次数)
最后X前面和X后面需要操作的次数相加即可。
完整代码