leetcode 926 将字符串翻转到单调递增

97 阅读1分钟

将字符串翻转到单调递增

如果一个二进制字符串,是以一些 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。

提示:

  • 1 <= s.length <= 105
  • s[i]'0''1'

解题

由题可知最终输出的字符串会有以下3中类型:0000,1111,0011

正序遍历s:

定义2个变量 prevZeroCountprevOneCount分别表示当前字符之前已有的0,1的个数,同时定义一个字典存储已遍历部分分别翻转为0000,1111,0011所需的次数 dic:{zero:0,one:0,zeroOne:0}

  • 当遇到0prevZeroCount += 1,此时已遍历部分是0000类型

  • 当遇到1时如果prevZeroCount === 0则,prevOneCount += 1,此时已遍历部分是1111类型

  • 否则需要计算已遍历部分需要翻转,计算需要反转次数

    • 转为成0000型:前序为0的+prevOneCount,(将待翻转的1全部翻转为0) ,即dic.zero + prevOneCount
    • 转为成1111型:前序为0或1的最小值+prevZeroCount,(将待翻转的0全部翻转为1),即min(dic.zero + dic.one) + prevZeroCount
    • 转为成0011型: 前序为0或1或01的最小值+prevZeroCount,(将待翻转的0全部翻转为1),即min(dic.zero + dic.one + dic.zeroOne) + prevZeroCount

    同时将prevZeroCount 重置为0prevOneCount重置为1(当前字符为1)

遍历结束后取min(dic.zero + dic.one + dic.zeroOne)为最小翻转次数

代码实现:

var minFlipsMonoIncr = function (s) {
  let prevZeroCount = 0,
    prevOneCount = 0,
    dic = { zero: 0, one: 0, zeroOne: 0 },
    start = 0,
    end = s.length - 1
  while (s[start] == '0' || s[end] == '1') { // 排除左边的0和右边的1最终会剩下101010这样的一组数据
    if (s[start] == '0') {
      start += 1
    }
    if (s[end] == '1') {
      end -= 1
    }
  }
  for (var i = start; i <= end; i++) {
    if (s[i] === '0') {
      prevZeroCount += 1
    } else {
      if (prevZeroCount === 0) {
        prevOneCount += 1
      } else {
        var tmpZero = dic.zero + prevOneCount
        var tmpOne = Math.min(dic.one, dic.zeroOne) + prevZeroCount
        var tmoZeroOne = Math.min(dic.zero, dic.one, dic.zeroOne) + prevZeroCount
        dic.zero = tmpZero
        dic.one = tmpOne
        dic.zeroOne = tmoZeroOne
        prevZeroCount = 0
        prevOneCount = 1
      }
    }
  }
  dic.zero += prevOneCount
  dic.one = Math.min(dic.one, dic.zeroOne) + prevZeroCount
  dic.zeroOne = Math.min(dic.zero, dic.one, dic.zeroOne) + prevZeroCount
  return Math.min(dic.zero, dic.one, dic.zeroOne)
}

时间复杂度O(n)