最长合法子串长度
[题目链接](https://www.nowcoder.com/practice/bda1d9a196644a66a233ab91144b41d4)
思路
给定一个 01 字符串,每次操作可以将一个 '1' 变成 '0',最多执行 次操作。要求最小化操作后最长全 1 子串的长度。
"最小化最大值" 是经典的二分答案模型。
二分答案
二分目标值 ,表示"操作后最长全 1 子串长度不超过
",然后贪心判断是否可行。
贪心判定
先预处理出所有极长全 1 段的长度。对于一段长度为 的全 1 段,我们要在其中放置若干个
'0'(即执行若干次操作),使得每一段剩余的全 1 子串长度不超过 。
关键观察:每次操作将一个 '1' 变为 '0',这个 '0' 本身占据一个位置,所以它既"切割"了连续段,又"消耗"了一个长度。
设需要 次操作,则:
- 产生
段全 1 子串;
- 总长度为
(因为
个位置变成了
'0'); - 最优策略是均匀切割,使最长段长度为
。
要满足 ,等价于
,即:
$$
所以对长度为 的段,所需操作次数为:
$$
将所有段所需的操作次数求和,若总和 ,则
可行。
二分范围
- 下界:
(把所有
'1'全变成'0'); - 上界:最长全 1 段的长度(不做任何操作)。
样例演示
字符串 "101110110",。
全 1 段长度为 。
- 尝试
:段长 1 需要
次,段长 3 需要
次,段长 2 需要
次,共
,可行。
- 尝试
:段长 1 需要
次,段长 3 需要
次,段长 2 需要
次,共
,不可行。
答案为 。
复杂度
- 时间复杂度:
,其中
为字符串长度。二分次数
,每次判定扫描所有段
。
- 空间复杂度:
,存储所有全 1 段的长度。
代码
class Solution {
public:
int maxLen(string s, int k) {
vector<int> segs;
int n = s.size();
int i = 0;
while (i < n) {
if (s[i] == '1') {
int j = i;
while (j < n && s[j] == '1') j++;
segs.push_back(j - i);
i = j;
} else {
i++;
}
}
if (segs.empty()) return 0;
int lo = 0, hi = *max_element(segs.begin(), segs.end());
while (lo < hi) {
int mid = (lo + hi) / 2;
long long ops = 0;
for (int len : segs) {
if (len > mid) {
if (mid == 0) {
ops += len;
} else {
long long need = (long long)len - mid;
long long div = (long long)mid + 1;
ops += (need + div - 1) / div;
}
}
}
if (ops <= k) hi = mid;
else lo = mid + 1;
}
return lo;
}
};
import java.util.*;
public class Solution {
public int maxLen (String s, int k) {
List<Integer> segs = new ArrayList<>();
int n = s.length();
int i = 0;
while (i < n) {
if (s.charAt(i) == '1') {
int j = i;
while (j < n && s.charAt(j) == '1') j++;
segs.add(j - i);
i = j;
} else {
i++;
}
}
if (segs.isEmpty()) return 0;
int lo = 0, hi = 0;
for (int len : segs) hi = Math.max(hi, len);
while (lo < hi) {
int mid = (lo + hi) / 2;
long ops = 0;
for (int len : segs) {
if (len > mid) {
if (mid == 0) {
ops += len;
} else {
long need = (long) len - mid;
long div = (long) mid + 1;
ops += (need + div - 1) / div;
}
}
}
if (ops <= k) hi = mid;
else lo = mid + 1;
}
return lo;
}
}

京公网安备 11010502036488号