目标
给你一个 二进制字符串 s。
你可以对这个字符串执行 任意次 下述操作:
- 选择字符串中的任一下标 i( i + 1 < s.length ),该下标满足 s[i] == '1' 且 s[i + 1] == '0'。
- 将字符 s[i] 向 右移 直到它到达字符串的末端或另一个 '1'。例如,对于 s = "010010",如果我们选择 i = 1,结果字符串将会是 s = "000110"。
返回你能执行的 最大 操作次数。
示例 1:
输入: s = "1001101"
输出: 4
解释:
可以执行以下操作:
选择下标 i = 0。结果字符串为 s = "0011101"。
选择下标 i = 4。结果字符串为 s = "0011011"。
选择下标 i = 3。结果字符串为 s = "0010111"。
选择下标 i = 2。结果字符串为 s = "0001111"。
示例 2:
输入: s = "00111"
输出: 0
说明:
- 1 <= s.length <= 10^5
- s[i] 为 '0' 或 '1'。
思路
有一个二进制字符串 s,每次操作可以选择一个下标 i,满足 s[i] == '1' 且 s[i + 1] == '0',将 s[i] 向右移直到遇到另一个 1 或者到达末尾,返回可以执行的最大操作次数。
要使操作次数最大,每组相邻的 0 都要为其前面的 1 提供一次操作。换句话说操作尽量不要让右侧的 0 过早的合并,累加每组相邻的 0 前面 1 的个数即可。
计算前缀 1 个数,正序遍历,第一次遇到 0 时,就加上前面 1 的个数,跳过相邻的 0(因为每次操作都要移到最右侧,相邻的 0 对每个 1 只能贡献一次操作)。
代码
/**
* @date 2025-11-13 8:44
*/
public class MaxOperations3228 {
public int maxOperations(String s) {
int n = s.length();
char[] chars = s.toCharArray();
int[] prefix = new int[n + 1];
int res = 0;
for (int i = 1; i <= n; i++) {
prefix[i] = prefix[i - 1] + (chars[i - 1] - '0');
}
int i = 0;
while (i < n) {
if (chars[i] == '0') {
res += prefix[i];
}
while (i < n && chars[i++] == '0') {
}
}
return res;
}
}
性能
