在问 · 算法题解

1004. 最大连续1的个数 III

题目描述

输入一个只含 0 和 1 的数组 nums,以及整数 k。

你最多可以把 k 个 0 改成 1。返回改完之后数组中最长一段连续 1 的长度。

示例 1
输入:nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
输出:6

解释:把下标 4、5 的两个 0 改成 1,得到下标 4 到 9 这段长度为 6 的全 1 段。

示例 2
输入:nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], k = 3
输出:10

解释:把下标 4、5、9 的 0 改成 1,下标 2 到 11 连成长度 10 的全 1 段。

数据范围

  • 1 <= nums.length <= 10^5
  • nums[i] 是 0 或 1。
  • 0 <= k <= nums.length

解题思路:滑动窗口

问题等价于:找最长的子数组,其中 0 的个数不超过 k。用滑动窗口:右端逐个扩展并统计窗口内 0 的个数 zeros;一旦 zeros > k,就移动左端直到 zeros ≤ k。每个右端对应的合法窗口长度都参与更新答案。

为什么正确

每次更新答案时,窗口 [left, right] 内 0 的个数 ≤ k,且 left 是该右端能取的最小左端。

复杂度分析

时间 O(n),左右指针都只右移;空间 O(1)。

易错点

收缩左端时只有移出的是 0 才把 zeros 减一;k = 0 时窗口只能包含 1。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def longestOnes(self, nums: List[int], k: int) -> int:
        left = zeros = ans = 0
        for right, x in enumerate(nums):
            if x == 0:
                zeros += 1
            while zeros > k:
                if nums[left] == 0:
                    zeros -= 1
                left += 1
            ans = max(ans, right - left + 1)
        return ans

载入编辑器,自己跑一遍 →

其他解法

两种方法都基于同一转化(区间内 0 的个数不超过 k)。二分法对每个右端点独立求最左端;滑动窗口利用左端点随右端点单调右移的性质,把二分省掉,达到线性时间。

解法 2:前缀和 + 二分查找 时间 O(n log n),空间 O(n)

把题目转化为:找最长的区间,使其中 0 的个数不超过 k。用 pre[i] 记录前 i 个元素中 0 的个数,区间 [l, r] 中 0 的个数为 pre[r+1] - pre[l]。pre 单调不减,所以对每个右端点 r,可以二分出最小的 l 使 pre[r+1] - pre[l] ≤ k,用 r - l + 1 更新答案。

思路清晰,展示了“前缀和单调时可以二分”的通用技巧。比滑动窗口多一个 log 因子,并需要额外的前缀和数组。

class Solution:
    def longestOnes(self, nums: List[int], k: int) -> int:
        n = len(nums)
        pre = [0] * (n + 1)
        for i, x in enumerate(nums):
            pre[i + 1] = pre[i] + (1 - x)
        ans = 0
        for right in range(n):
            lo, hi = 0, right + 1
            while lo < hi:
                mid = (lo + hi) // 2
                if pre[right + 1] - pre[mid] <= k:
                    hi = mid
                else:
                    lo = mid + 1
            ans = max(ans, right - lo + 1)
        return ans

二分查找 专题的其他题目

查看 二分查找 全部题目 →