给定一个由若干 0
和 1
组成的数组 A
,我们最多可以将 K
个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。
1.题意是要返回 1 的最长连续子数组的长度 连续 就可以想到窗口了
最多可以把k个0转化成1。
解决主要思想就是:一开始维护一个0小于k的窗口,右指针不断向右遍历,如果窗口中0的个数>k(也就是0的个数为k+1时),移动左指针,窗口不断变小,直到窗口中0的个数等于k,左指针停止移动,继续移动右指针。
题意就可以转化为 如果当前的窗口的左边界是l,右边界是right。
假设 K > 0; l = 0, r = 0开始。
假设窗口内的0是小于等于k的。
r向右遍历,如果nums[r] == 0, 判断 一下当前窗口中的个数是否>K
-
如果 >k ,移动左指针减少0的个数,直到窗口中的0的个数为k时停止,更新答案继续移动右指针。
-
<=k 更新答案继续移动右指针。
public int longestOnes(int[] nums, int k) {
int n = nums.length;
int l = 0,r = 0;
int ans = 0;
int sum = 0;
while(r < n){
sum += (1- nums[r]);
while(sum > k){
sum -= (1-nums[l++]);
}
ans = Math.max(ans,++r-l);
}
return ans;
}
-
因为题意只是让我们找最长连续子区间的长度,如果我当前的最长子序列长度已经为m了,那么小于m的区间就不用再去看是否满足条件了。看>m的连续子序列长度是否有满足条件的
public int longestOnes(int[] nums, int k) {
int n = nums.length;
// 此时长度为r-l == 0
int l = 0,r = 0;
int sum = 0;
while(r < n){
// 1. 满足0的个数<=k 直接r++;
// 2. 0的个数>k 此时最小子区间为[l,r-1],长度为r-l了,比这个长度小的就不用再去检查0的个数是否小于等于k了 l++ 如果nums[l] == 0 sum--; nums[l] == 1,sum不变,保证区间长度等于m。 这是一种贪心的思想,长度已经不可能比m小了,在 一次sum += (1- nums[r++]); 一次 sum -= (1-nums[l++]);if sum <=k ,l就停止不动了 r继续++ 此时长度会比m更大
sum += (1- nums[r++]);
if(sum > k){
sum -= (1-nums[l++]);
}
}
// r - l 代表的是从[0,r]中的1的最长连续子区间的长度 r-l不会减小,只会增大,最后返回的这个肯定为最大值 贪心的思想 省去每次r++需要重新计算最长连续子区间的长度的步骤
return r-l;
}