目录
【算法题】最少翻转次数使字符串相等 — 翻转后缀二进制字符串问题解析
【算法题】最少翻转次数使字符串相等 — 翻转后缀二进制字符串问题解析
题目描述
给定一个长度为 n 的二进制字符串 target
,下标从 0 开始。你拥有另一个长度为 n 的二进制字符串 s
,最初 s
的每一位都是 0
。
你的目标是通过若干次操作,使得字符串 s
变得和 target
一样。
操作规则:
- 你可以选择一个下标
i
(0 <= i < n
),翻转从位置i
到位置n-1
之间的所有位。 - 翻转的定义是:
0
变为1
,1
变为0
。
问:为了使 s
和 target
相等,最少需要多少次翻转操作?
题目分析
这道题的关键是理解翻转操作对字符串状态的影响:
- 一次操作会影响从某个位置
i
到字符串末尾所有的位。 - 操作次数和位置选择都会影响最终的字符串状态。
如果按字面意思模拟翻转操作,会很耗时,因为每次翻转需要操作后缀的所有位。对于大数据,这种模拟不可行。
因此,我们需要一个简洁的策略:
- 观察从左到右,字符串
s
从全0
开始。 - 翻转会改变当前位置及其后的所有位。
- 只要当前位置和目标字符串不同,就需要翻转一次。
这启发我们采用贪心算法,沿着字符串从左到右处理:
- 维护一个变量记录当前
s
的实际状态。 - 遍历
target
:
-
- 如果当前位置
target[i]
和当前状态不一致,说明必须翻转后缀。 - 翻转次数加一,同时更新当前状态为目标字符。
- 如果当前位置
解题方法
- 初始化:
-
flips = 0
,表示操作次数。cur = '0'
,表示当前字符串s
的实际状态(初始全0)。
- 遍历字符串
target
:
-
- 对每个字符
ch
:
- 对每个字符
-
-
- 若
ch != cur
,说明当前位置的s
需要翻转才能与target
对应。
- 若
-
-
-
-
flips += 1
,记录一次操作。cur = ch
,更新当前状态,表示经过翻转后,从当前位置开始的状态变为ch
。
-
-
- 返回
flips
即为答案。
复杂度分析
- 时间复杂度:
O(n)
,只需一次遍历字符串。 - 空间复杂度:
O(1)
,只使用常数个变量。
相比模拟翻转字符串,每次操作需要翻转子串,效率更高。
代码实现(Python)
class Solution:
def minFlips(self, target: str) -> int:
flips = 0
cur = '0' # 当前实际状态
for ch in target:
if ch != cur:
flips += 1
cur = ch # 状态切换
return flips
示例说明
示例 1:
target = "10111"
初始 s = "00000"
遍历过程:
i | target[i] | cur | 不同? | flips | 说明 |
0 | '1' | '0' | 是 | 1 | 翻转后缀 [0..4],s变为11111 |
1 | '0' | '1' | 是 | 2 | 翻转后缀 [1..4],s变为10000 |
2 | '1' | '0' | 是 | 3 | 翻转后缀 [2..4],s变为10111 |
3 | '1' | '1' | 否 | 3 | 无需翻转 |
4 | '1' | '1' | 否 | 3 | 无需翻转 |
最终翻转次数:3
总结与思考
- 本题关键是避免直接模拟翻转,通过维护一个“当前状态”变量,贪心地翻转位置,使时间复杂度降为线性。
- 这种“状态切换”的思路在类似“区间翻转”、“位反转”问题中也很常见。
- 通过分析状态变化,可以有效推导最优解。