LeetCode探索(88):926-将字符串翻转到单调递增

117 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情

题目

如果一个二进制字符串,是以一些 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 <= 10^5
  • s[i]'0''1'

思考

本题难度中等。

首先是读懂题意。对于一个二进制字符串s,我们需要将任何0翻转为1或者将1翻转为0,使其满足单调递增的条件。最终我们返回使s单调递增的最小翻转次数。

我们可以使用前缀和的方法。我们利用前缀和可以快速地计算出当遍历到当前字符时,前面的1有多少个以及后面的0有多少个。我们先计算前缀和数组preSumpreSum[i] 表示索引i前面有几个数字1。假设最终答案是x个0和n-x个1,当x=3时,可知 preSum[3]=1,左边1个1,需要1次翻转。右边1的数量是preSum[n]-preSum[x]=2,0的数量是(n-x)-(preSum[n]-preSum[x])=1,需要1次翻转。

解答

方法一:前缀和

/**
 * @param {string} s
 * @return {number}
 */
var minFlipsMonoIncr = function(s) {
  const n = s.length
  let preSum = new Array(n + 1).fill(0) // 数组长度是n+1
  for (let i = 0; i < n; i++) {
    preSum[i+1] = preSum[i] + (s[i] === '1' ? 1 : 0)
  }
  let ans = Number.MAX_SAFE_INTEGER
  for (let i = 0; i <= n; i++) {
    ans = Math.min(ans, preSum[i] + n-i-(preSum[n]-preSum[i]))
  }
  return ans
}

// 执行用时:76 ms, 在所有 JavaScript 提交中击败了87.69%的用户
// 内存消耗:47.2 MB, 在所有 JavaScript 提交中击败了72.31%的用户
// 通过测试用例:93 / 93

复杂度分析:

  • 时间复杂度:O(n),其中 n 为字符串s的长度。
  • 空间复杂度:O(n)。

参考