原题链接
题目描述:
给你一个01字符串,定义答案=该串中最长的连续1的长度,现在你有至多K次机会,每次机会可以将串中的某个0改成1,现在问最大的可能答案
输入描述:
输入第一行两个整数N,K,表示字符串长度和机会次数(1 <= N <= 300000, 0 <= K <= N) 第二行输入N个整数,表示该字符串的元素。
输出描述:
输出一行表示答案
示例1
输入
10 2
1 0 0 1 0 1 0 1 0 1
输出
5
方法一 动态规划
本题是属于简单的一维动态规划,首先我们需要搞清楚的是,题目要求的最长的全1串是通过将最多K个0改成1后得到的。
如果字符串中的0的数量不超过K, 那么答案就是字符串的长度,因为我们可以把所有的0修改成1。
如果0的数量超过了K,那我们怎么修改得到结果呢? 答案是:我们一定要修改隐藏1后的串中连续K个0才可能出现要求的最长全1串。
简单证明一下: 必须连续K个0,如果不连续,那么中间会有0断开全1串,那么一定不会大于修改连续K个0的结果。 必须是K,如果修改不到K次,那么一定不会大于修改K次的结果。
综上,我们的思路就很清晰了。 对于示例1
01串的位置:0 1 2 3 4 5 6 7 8 9
隐藏1后0串: 0 0 0 0 0
01原字符串:1 0 0 1 0 1 0 1 0 1
用f[x]记录第x个0在串中的位置。
f[1]=1, f[2]=2, f[3]=4, f[4]=6, f[5]=8
下标 i 遍历 01 串区间 [0, N),如果当前的 0 的数量 x 不大于 K ,那么以位置 i 结尾的最长的全1串长度为 i + 1。
如果当前0的数量x超过K,那么以位置i结尾得到的最长全1串的长度,就是我们从i向前修改连续K个0后的结果,长度为:当前位置i - 第 x-K 个0在串中的位置 即 i - f[x-K],我们用ans不断更新这两个结果,最后遍历结束就是最终的答案。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 300000 + 1;
int f[MAXN], ans = 0;
int main() {
int N, K, num, count = 0;
scanf("%d%d", &N, &K);
for(int i = 0; i < N; ++i) {
scanf("%d", &num);
if(num == 0) f[++count] = i;
if(count <= K) ans = max(i+1, ans);
else ans = max(i - f[count - K], ans);
}
printf("%d", ans);
return 0;
}
复杂度
- 时间复杂度:
- 空间复杂度:
方法二 双指针
由于本题特殊性,可以用双指针来解,具体的,两个指针维护中间 0 个数,右指针每次右移一步。当中间 0 个数超过 k 时候,左指针向右移动一次。最后两个指针的距离就是最长全 1 串长度。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 300000 + 1;
int num[MAXN];
int main() {
int N, K;
scanf("%d%d", &N, &K);
int i, j, con = 0;
for(i = 0, j = 0; i < N; ++i) {
scanf("%d", &num[i]);
if(!num[i]) ++con;
if(con > K && !num[j++]) --con;
}
printf("%d", i-j);
return 0;
}
复杂度
- 时间复杂度:
- 空间复杂度: