思路分析
用「左右指针」维护一个滑动窗口,窗口内允许包含最多 k 个 0(翻转成 1 后就是全 1 子数组),通过调整窗口的左右边界,找到满足条件的最大窗口长度:
- 右指针右移:遍历数组,逐个将元素纳入窗口,统计窗口内 0 的数量zeroCount;
- 左指针右移:当zeroCount > k时,说明窗口内 0 的数量超过允许翻转的次数,需要右移左指针,直到zeroCount ≤ k;
更新最大长度:每轮遍历都计算当前窗口长度(right - left + 1),并更新全局最大值。
代码实现
java
public int longestOnes(int[] nums, int k) {
// 定义左右指针
int left = 0, right = 0;
// 定义最大长度
int maxLength = 0;
// 定义0的数量
int zeroNum = 0;
while (right < nums.length){
// 更新零的数量
if (nums[right] == 0) {
zeroNum++;
}
while (zeroNum > k){
if (nums[left] == 0) {
zeroNum--;
}
left++;
}
maxLength = Math.max(maxLength, right - left + 1);
++right;
}
return maxLength;
}
复杂度分析
- 时间复杂度:O(n) → 每个元素最多被左、右指针各访问一次,总操作次数 2n;
- 空间复杂度:O(1) → 仅使用常数个变量,无额外空间开销。
实例分析
示例 1:nums = [1,1,1,0,0,0,1,1,1,1,0],k = 2
遍历过程关键步骤:
right=0-2(元素 1,1,1):zeroCount=0 → 窗口长度 3,maxLen=3;
right=3(元素 0):zeroCount=1 ≤2 → 窗口长度 4,maxLen=4;
right=4(元素 0):zeroCount=2 ≤2 → 窗口长度 5,maxLen=5;
right=5(元素 0):zeroCount=3 >2 → 收缩左指针:
left=0(1)→ left++,zeroCount 仍 3;
left=1(1)→ left++,zeroCount 仍 3;
left=2(1)→ left++,zeroCount 仍 3;
left=3(0)→ left++,zeroCount=2;
此时窗口:left=4,right=5 → 长度 2;
right=6-9(元素 1,1,1,1):zeroCount=2 → 窗口长度 = 9-4+1=6,maxLen=6;
right=10(元素 0):zeroCount=3 >2 → 收缩左指针到 5,zeroCount=2 → 窗口长度 = 10-5+1=6;