题目链接
题目描述
给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。
示例 1:
输入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:
[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
示例 2:
输入:A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
输出:10
解释:
[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 10。
提示:
1 <= A.length <= 20000
0 <= K <= A.length
A[i] 为 0 或 1
思路
将问题进行转换,把“最多可以把 K 个 0 变成 1,求仅包含 1 的最长子数组的长度”转换为“找出一个最长的子数组,该子数组内最多允许有 K 个 0 ”。
因为是求最大连续子区间,可以使用滑动窗口。滑动窗口的限制条件是:窗口内最多有 K 个 0。
具体实现时使用两个指针left、right,分别指向滑动窗口的左右端点,用nowzero记录零的个数。
- 当遇到值为0且nowzero未满时,right往右移一个位置,零的个数nowzero加1;
- 当遇到值为0且nowzero已满时,先调整left直到nowzero不满为止,再将right往右移一个位置,零的个数nowzero加1;
- 当遇到值为1时,直接right往右移一个位置即可。
代码如下:
class Solution {
public:
int longestOnes(vector<int>& A, int K) {
int ans=0,nowzero=0,left=0,right=0;
for(auto i:A){
ans=max(ans,right-left);
//遇到值为0且nowzero未满时,right往右移一个位置,零的个数nowzero加1;
if(i==0&&nowzero<K){
right++;
nowzero++;
}
//遇到值为0且nowzero已满时,先调整left直到nowzero不满为止,再将right往右移一个位置,零的个数nowzero加1;
else if(i==0&&nowzero>=K){
while(nowzero>=K){
if(A[left]==0)
nowzero--;
left++;
}
right++;
nowzero++;
}
//遇到值为1时,直接right往右移一个位置即可
else
right++;
}
ans=max(ans,right-left);
return ans;
}
};
当然也可以合并前面两个条件判断,代码如下:
class Solution {
public:
int longestOnes(vector<int>& A, int K) {
int ans=0,nowzero=0,left=0,right=0;
for(auto i:A){
ans=max(ans,right-left);
if(i==0){
while(nowzero>=K){
if(A[left]==0)
nowzero--;
left++;
}
right++;
nowzero++;
}
else
right++;
}
ans=max(ans,right-left);
return ans;
}
};