作者: 负雪明烛
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. memset初始化值的效率秒杀for循环

    <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...

  2. JVM1 JVM与Java体系结构

    目录 JVM与Java体系结构 虚拟机与Java虚拟机 虚拟机 Java虚拟机 JVM的位置 JVM的整体结构 Java代码执行流程 JVM的架构模型 基于栈的指令级架构 基于寄存器的指令级架构 两种 ...

  3. 关于java中的安全管理器

    最近再查看java的源码的时候看见了这一类代码 final SecurityManager sm = System.getSecurityManager(); 想要了解这个是为了做什么,查看资料之后发 ...

  4. flink---实时项目--day01--1. openrestry的安装 2. 使用nginx+lua将日志数据写入指定文件中 3. 使用flume将本地磁盘中的日志数据采集到的kafka中去

    1. openrestry的安装 OpenResty = Nginx + Lua,是⼀一个增强的Nginx,可以编写lua脚本实现⾮非常灵活的逻辑 (1)安装开发库依赖 yum install -y ...

  5. iOS-调用系统的短信和发送邮件功能,实现短信分享和邮件分享

    一.邮件分享 1.iOS系统自带邮件设置邮箱(此处以QQ邮箱为例)(http://jingyan.baidu.com/album/6181c3e084cb7d152ef153b5.html?picin ...

  6. spring jdbc 配置数据源连接数据库

    概述 在XML配置数据源,并将数据源注册到JDBC模板 JDBC模板关联业务增删改查 在XML配置数据源 <?xml version="1.0" encoding=" ...

  7. vue-cli2嵌入html

    1.使用iframe <!-- 相对路径/绝对路径 --> <iframe src="../../../static/zsw.html"></ifra ...

  8. 理解css中的 content:" " 是什么意思

    css中的属性是插入生成的内容,它一般与伪元素:befor和 :after 配合使用. content:"." 就表示在需要的地方插入"." 注意:如果已经规定 ...

  9. Linux 目录结构及详细操作

    目录 Linux 目录结构及详细操作 目录结构 目录结构的特点 目录结构挂载 目录结构发展 关闭selinux(了解) 重要目录说明(etc目录说明) 1.网卡配置文件 2.解析配置文件 3.主机名称 ...

  10. ciscn_2019_s_6

    例行检查 没有开启nx保护,考虑用shellcode来做这道题 程序放入ida查看 我们可以输入48个字符覆盖0使printf打印出bp的值 继续看这里,buf的大小实际上只有0x38的大小,但是re ...