当前位置: 首页 > news >正文

将字符串翻转到单调递增

我们先来看题目描述:

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

解决方案:动态规划

单调递增的字符串满足以下性质:

  • 首个字符是 0 或 1;
  • 其余的每个字符,字符 0 前面的相邻字符一定是 0,字符 1 前面的相邻字符可以是 0 或 1。

当 i>0 时,如果字符串 s 的长度为 i 的前缀即 s[0..i−1] 单调递增,且 s[i] 和 s[i−1] 也满足上述单调递增的顺序,则长度为 i+1 的前缀 s[0..i] 也单调递增。因此可以使用动态规划计算使字符串 s 单调递增的最小翻转次数。

由于字符串 s 的每个位置的字符可以是 0 或 1,因此对于每个位置需要分别计算该位置的字符是 0 和该位置的字符是 1 的情况下的最小翻转次数。

假设字符串 s 的长度是 n,对于 0≤i<n,用 dp[i][0] 和 dp[i][1] 分别表示下标 i 处的字符为 0 和 1 的情况下使得 s[0..i] 单调递增的最小翻转次数。

当 i=0 时,对应长度为 1 的前缀,一定满足单调递增,因此 dp[0][0] 和 dp[0][1] 的值取决于字符 s[i]。

具体而言,dp[0][0]=II(s[0]=‘1’),dp[0][1]=II(s[0]=‘0’),其中 II 为示性函数,当事件成立时示性函数值为 1,当事件不成立时示性函数值为 0。

当 1≤i<n 时,考虑下标 i 处的字符。如果下标 i 处的字符是 0,则只有当下标 i−1 处的字符是 0 时才符合单调递增;

如果下标 i 处的字符是 1,则下标 i−1 处的字符是 0 或 1 都符合单调递增,此时为了将翻转次数最小化,应分别考虑下标 i−1 处的字符是 0 和 1 的情况下需要的翻转次数,取两者的最小值。

实现方面有以下两点可以优化。

1. 可以将边界情况定义为 dp[−1][0] = dp[−1][1] = 0,则可以从下标 0 开始使用状态转移方程计算状态值。

2. 由于 dp[i−1] 有关,因此在计算状态值的过程中只需要维护前一个下标处的状态值,将空间复杂度降低到 O(1) 。

代码

Python3

class Solution: def minFlipsMonoIncr(self, s: str) -> int: dp0 = dp1 = 0 for c in s: dp0New, dp1New = dp0, min(dp0, dp1) if c == '1': dp0New += 1 else: dp1New += 1 dp0, dp1 = dp0New, dp1New return min(dp0, dp1)

Java

class Solution { public int minFlipsMonoIncr(String s) { int n = s.length(); int dp0 = 0, dp1 = 0; for (int i = 0; i < n; i++) { char c = s.charAt(i); int dp0New = dp0, dp1New = Math.min(dp0, dp1); if (c == '1') { dp0New++; } else { dp1New++; } dp0 = dp0New; dp1 = dp1New; } return Math.min(dp0, dp1); } }

C#

public class Solution { public int MinFlipsMonoIncr(string s) { int n = s.Length; int dp0 = 0, dp1 = 0; for (int i = 0; i < n; i++) { char c = s[i]; int dp0New = dp0, dp1New = Math.Min(dp0, dp1); if (c == '1') { dp0New++; } else { dp1New++; } dp0 = dp0New; dp1 = dp1New; } return Math.Min(dp0, dp1); } }
http://www.jsqmd.com/news/1087305/

相关文章:

  • VSCode + PlantUML:从零构建专业级UML类图
  • 踩了三天坑,我决定重新写
  • 一阶段多目标跟踪新范式:FairMOT如何实现检测与ReID的高效统一
  • NB-IoT技术详解:低功耗、广覆盖,物联网场景的核心网络技术
  • 终极字体库指南:15款专业字体一键获取与安装教程 [特殊字符]
  • 2024蓝桥杯网络安全赛项核心考点与实战WriteUp精析
  • 赛博朋克2077终极存档编辑器:免费修改夜之城的完整指南
  • 【多目标跟踪技术演进】从TransTrack到MOTR:Transformer在MOT中的核心范式与实战解析
  • LX Music音源配置指南:5步解锁全网高品质音乐
  • 搞定 AI 编程工作台的后台分布式难题
  • 3000+戴森球计划工厂蓝图终极指南:从新手到专家的完整成长路径
  • 基于SpringBoot+Vue的招聘系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】
  • 深入解析CANFD模块状态机:从全局模式到通道模式的实战指南
  • Street Fighter 6在线对战软锁:一个游戏修改框架与在线游戏交互的警示案例
  • 这个级别的配置不够万国飞行员马克十八的老哥,建议先看看这处烧蓝指针的工艺核心软肋
  • H3C交换机基于ACL实现VLAN间安全隔离实战
  • Video2X终极指南:如何免费实现AI视频放大和帧率提升
  • ClickHouse 查询优化实战:从 MergeTree 索引到向量化引擎的深度调优
  • Qlib:用AI重构量化研究的开源平台
  • AFDM信号接收中的硬件损伤分析与LMMSE检测优化
  • 200-300元学生党耳机推荐:哪些产品更适合长期使用?
  • 如何在浏览器中零成本创建专业EPUB电子书:完整指南
  • 零基础入门 AI,码士集团人工智能零基础班真的能学会吗
  • openEuler虚拟机磁盘在线扩容实战:无需重启的LVM扩展指南
  • 【Geant4实战指南】—— 在Ubuntu上从零到一构建高能物理模拟环境
  • MIPI DSI命令模式序列操作:寄存器配置与工程调试全解析
  • 终极指南:如何用Illustrator脚本提升设计效率300%
  • 7-Zip:解决你文件管理难题的免费压缩神器
  • 5个方法彻底解决ExplorerPatcher导致的Windows资源管理器崩溃问题:终极修复指南
  • 网络安全入门:从零搭建Metasploitable2靶机环境与漏洞利用实战