作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址:https://leetcode.com/problems/flip-string-to-monotone-increasing/description/

题目描述

A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possibly 0), followed by some number of '1's (also possibly 0.)

We are given a string S of '0's and '1's, and we may flip any '0' to a '1' or a '1' to a '0'.

Return the minimum number of flips to make S monotone increasing.

Example 1:

Input: "00110"
Output: 1
Explanation: We flip the last digit to get 00111.

Example 2:

Input: "010110"
Output: 2
Explanation: We flip to get 011111, or alternatively 000111.

Example 3:

Input: "00011000"
Output: 2
Explanation: We flip to get 00000000.

Note:

  1. 1 <= S.length <= 20000
  2. S only consists of ‘0’ and ‘1’ characters.

题目大意

一个字符串中有0有1,问最少翻转多少个字符能够使得这个字符串编程一个单调递增的字符串。

解题方法

Prefix计算

周赛第二题,这个题还是有点难度的,不好想。

常规的做法是,我们使用Prefix数组保存每个位置之前的1有多少个。因为我们最终的目标是变成前面是0后面是1的字符串,所以,可以通过过一遍数组,要把遍历到的位置前面都变0后面都变1,需要计算每个位置前面有多少个1加上后面有多少个0。因为前面的1要翻转成0,后面的0要翻转成1.

总之,只需要先求出每个位置前面的1的个数是多少,那么,再次遍历,求每个位置前面的1个数和后面0个数的和的最小值即可。

使用的是P数组保存每个位置前面1的个数。那么后面0的个数是:总的0的个数(即,总个数减去总的1的个数) - 前面0的个数(即,现在的位置索引减去前面1的个数)。

时间复杂度是O(N),空间复杂度是O(N).

class Solution(object):
def minFlipsMonoIncr(self, S):
"""
:type S: str
:rtype: int
"""
N = len(S)
P = [0] # how many ones
res = float('inf')
for s in S:
P.append(P[-1] + int(s))
return min(P[i] + (N - P[-1]) - (i - P[i]) for i in range(len(P)))

动态规划

工位对面的大师想出来的方法,我自愧不如啊,看了很久还要请教一下才能勉强弄懂出来的样子。

这个题和买卖股票有点类似,都需要使用一个二维dp数组,分别保存的是以0结尾或者以1结尾的字符串需要翻转的最小次数。

为了方便,给dp数组多了一个空间,表示最前面的字符串还没有开始的时候,肯定不需要做任何翻转。

那么,当我们遍历到字符串的i位置时:

  1. 如果这个位置的字符是'0',那么:
  • 当前以0结尾的dp数组等于前面的以0结尾的dp,即不需要做任何操作,此时前面必须是0结尾;
  • 当前以1结尾的dp数组等于Min(前面的以0结尾的dp + 1,前面的以1结尾的dp + 1)。这里的含义是一种情况为前面的0到前面的那个位置结束,把当前的0翻转成1;另一种情况是前面一位以1结束不变,把当前的0翻转成1。需要求这两个情况的最小值。此时前面可以以0或者1结尾。
  1. 如果这个位置的字符是'1',那么:
  • 当前以0结尾的dp数组等于前面的以0结尾的dp + 1,即把当前的1翻转成0,此时前面只能以0结尾;
  • 当前以1结尾的dp数组等于Min(前面的以0结尾的dp,前面的以1结尾的dp)。这里的含义是该位置以1结尾需要翻转多少次呢?当然是前面翻转0或者1的次数最小值,因为当前的1一定不用翻转,而前面无论怎么翻转都能满足条件。此时前面可以以0或者1结尾。

总结一下思路,首先一定要明白dp数组是代表以这个第二维度数字结尾的状态数,比如dp[i][0]就是第i个数字以0结尾的情况下,需要翻转的个数。然后,要明白的是如果遍历到的这个字符并没有限制死我们是否要翻转它,所以翻转不翻转都要考虑到,即这个对应位置变成1或者0两种情况下dp怎么更新。更新的方式是看前面一个状态,从前一个状态转成现在要变成的状态,需要做哪些操作,翻转次数怎么变化。

时间复杂度是O(N),空间复杂度是O(N).

class Solution(object):
def minFlipsMonoIncr(self, S):
"""
:type S: str
:rtype: int
"""
N = len(S)
dp = [[0] * 2 for _ in range(N + 1)]
for i in range(1, N + 1):
if S[i - 1] == '0':
dp[i][0] = dp[i - 1][0]
dp[i][1] = min(dp[i - 1][1], dp[i - 1][0]) + 1
else:
dp[i][0] = dp[i - 1][0] + 1
dp[i][1] = min(dp[i - 1][1], dp[i - 1][0])
return min(dp[N][0], dp[N][1])

显然,上面的做法中,每次dp转移操作只和前面的一个状态有关,所以,可以优化空间复杂度到O(1)。代码如下:

class Solution(object):
def minFlipsMonoIncr(self, S):
"""
:type S: str
:rtype: int
"""
N = len(S)
dp = [0] * 2
for i in range(1, N + 1):
if S[i - 1] == '0':
dp[0] = dp[0]
dp[1] = min(dp[1], dp[0]) + 1
else:
dp[1] = min(dp[1], dp[0])
dp[0] = dp[0] + 1
return min(dp[0], dp[1])

参考资料

https://leetcode.com/problems/flip-string-to-monotone-increasing/discuss/183859/Java-DP-using-O(N)-time-and-O(1)-space

日期

2018 年 10 月 21 日 —— 这个周赛有点难

【LeetCode】926. Flip String to Monotone Increasing 解题报告(Python)的更多相关文章

  1. [LeetCode] 926. Flip String to Monotone Increasing 翻转字符串到单调递增

    A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possibly 0), ...

  2. LC 926. Flip String to Monotone Increasing

    A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possibly 0), ...

  3. 【leetcode】926.Flip String to Monotone Increasing

    题目如下: A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possib ...

  4. 926. Flip String to Monotone Increasing

    A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possibly 0), ...

  5. [Swift]LeetCode926. 将字符串翻转到单调递增 | Flip String to Monotone Increasing

    A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possibly 0), ...

  6. Flip String to Monotone Increasing LT926

    A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possibly 0), ...

  7. LeetCode 606 Construct String from Binary Tree 解题报告

    题目要求 You need to construct a string consists of parenthesis and integers from a binary tree with the ...

  8. 【LeetCode】94. Binary Tree Inorder Traversal 解题报告(Python&C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 解题方法 递归 迭代 日期 题目地址:https://leetcode.c ...

  9. 【LeetCode】341. Flatten Nested List Iterator 解题报告(Python&C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归+队列 栈 日期 题目地址:https://lee ...

随机推荐

  1. R语言与医学统计图形-【11】ggplot2几何对象之散点图

    ggplot2绘图系统--几何对象之散点图 以geom开头的函数超过30个.几何对象和标度函数scale密不可分.只有在aes中传入某个变量,scale才能发挥作用. 所谓标度scale,就是图形遥控 ...

  2. mac系统升级导致VirtualBox报Kernel driver not installed (rc=-1908)

    一.背景 最近将我的Mac升级成了Monterey版本,结果发现之前的安装的VirtualBox虚拟机无法启动,报了如下错误. Kernel driver not installed (rc=-190 ...

  3. 8.7 进程间的通讯:管道、消息队列、共享内存、信号量、信号、Socket

    进程间的通讯 进程间为什么需要通讯? 共享数据.数据传输.消息通知.进程控制 进程间的通讯有哪些类型? 首先,联系前面讲过的知识,进程之间的用户地址空间是相互独立的,不能进行互相访问,但是,内核空间却 ...

  4. 巩固javaweb的第二十四天

    巩固内容: 提示用户信息 在验证失败之后通常需要提示用户错误信息,可以通过下面的代码完成: alert("地址长度大于 50 位!"); 当使用 alert 提示错误信息时,参数是 ...

  5. 一个专业处理字符串的IDEA插件

    字符串处理想必是小伙伴们平时开发时经常碰到的一个 "难题".为什么要打上引号?因为你说他难吧,其实也不是什么特别复杂的事:你说他不难吧,弄起来还真挺麻烦的,像删除其中空行啊.切换大 ...

  6. Activity 详解

    1.活动的生命周期 1.1.返回栈 Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈.栈是一种先进后出的数据结构,在默认情况下,每当我们启 ...

  7. mysql之join浅析

    1.可以使用join吗?使用join有什么问题呢?-- >超过3个表不使用join,笛卡尔积问题 -->这些问题是怎么造成的呢? 如果可以使用 Index Nested-Loop Join ...

  8. AT1980 [AGC001B] Mysterious Light 题解

    # 题意:高桥 くん 有一个边长为 N 的三枚镜子构成的正三角形 , 顶点为 a, b, c. 他有一个超级步枪 , 放在 AB 段的P点上,使得 AP=X . 并沿着平行于 BC 的方向发射一道光 ...

  9. centos部署配置gogs代码仓库

    目录 一.简介 二.部署 三.网页配置 一.简介 Gogs的目标是打造一个最简单.最快速和最轻松的方式搭建自助Git服务.使用Go语言开发使得Gogs能够通过独立的二进制分发,并且支持Go语言支持的 ...

  10. gitlab配置免密拉取推送

    目录 一.简介 二.配置 一.简介 gitlab默认提供HTTP/SSH两种请求方式下载代码 测试用的gitlab账号 账号:abc 密码:123456 二.配置 1.生成秘钥,一路回车即可 cd ~ ...