← 返回编程题库
coding-min-flips-monotone-pnl简单免费版2000ms未尝试

最少翻转使涨跌序列单调

Minimum Flips for Monotone Up-Day Pattern

开始编码

因子研究组在复盘一支资产连续 n 天的涨跌标记序列 ss[i] = '1' 表示第 i 天为涨日,s[i] = '0' 表示跌日。一个待检验的工作假设是区间存在制度切换——窗口前段全是回撤(连续跌日),后段全是反弹(连续涨日),即整体呈现 0...0 1...1 的单调形态(任一段允许为空)。为了量化这个假设与数据的契合度,他们想知道:最少需要重新标记多少天(把某天的 '0' 改成 '1' 或把 '1' 改成 '0'),才能让原序列恰好与「区间制度切换」模板对齐?这个最小翻转数越小,说明假设拟合得越好。

请实现 solution(s: str) -> int,返回最少翻转次数。规则:(1) 目标形态是任意 '0' * a + '1' * b,其中 a + b = na, b ≥ 0,因此全 '0' 与全 '1' 都属于合法目标;(2) 当输入本身就符合某个目标形态时,返回 0;(3) 翻转按位置独立计数,'0' → '1' 和 '1' → '0' 都恰好计 1。

示例solution("00110") 应返回 1。候选分界 k = 0, 1, 2, 3, 4, 5 对应的翻转代价分别是 3, 2, 1, 2, 3, 2。最小值在 k = 2 取到,目标形态是 "00111":只需翻转位置 4(把 '0' 改成 '1'),所以答案是 1。再看 solution("00011"):输入本身就符合 0...0 1...1 形态,无需翻转,返回 0。再举一个例子,solution("010110") 返回 2——一个最优目标是 "011111"(把位置 2 的 '0' 翻成 '1',把位置 5 的 '0' 翻成 '1')。

朴素的 O(n²) 做法(枚举每个分界 k,再扫一遍统计翻转)在 n = 10⁵ 时会超时。关键观察:把分界放在位置 k 之后,翻转代价拆成「前缀 s[0..k-1] 里的 '1' 数」加「后缀 s[k..n-1] 里的 '0' 数」。从左到右扫一遍 k:前缀里 '1' 的计数每遇到一个 '1' 就加 1,后缀里 '0' 的计数等于「全串 '0' 总数 − 前缀里 '0' 的数量」。一遍扫描配两个标量计数器即可——O(n) 时间、O(1) 额外空间。这是动态规划在最简单情形的退化形态:状态只有常数个标量。

约束条件

  • 1 ≤ len(s) ≤ 100000
  • s 中每个字符是 '0'(跌日)或 '1'(涨日)
  • 返回最少的单字符翻转次数,使得翻转后字符串里所有 '0' 都在所有 '1' 之前(即字符串非递减)
  • 已经单调的输入(包括全 '0'、全 '1')返回 0
  • 返回值是 int,要求精确匹配

样例

Case 1 · needs one flip

输入: ["00110"]

期望: 1

候选分界 k=0..5 对应代价 3,2,1,2,3,2,最小值 1 在 k=2 取到,目标形态 "00111",仅翻位置 4 的 '0' 为 '1'。

Case 2 · already monotone — no flips

输入: ["00011"]

期望: 0

输入已经是 0...0 1...1 形态,无需翻转,返回 0。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · needs one flip

输入: ["00110"]

期望: 1

候选分界 k=0..5 对应代价 3,2,1,2,3,2,最小值 1 在 k=2 取到,目标形态 "00111",仅翻位置 4 的 '0' 为 '1'。

Case 2 · already monotone — no flips

输入: ["00011"]

期望: 0

输入已经是 0...0 1...1 形态,无需翻转,返回 0。