LeetCode 1004. 最大连续1的个数 III

18 阅读3分钟

题目链接

1004. 最大连续1的个数 III

题目描述

宝子们,给你们一个二进制数组 nums 和一个整数 k,咱们要找最长的连续1的子数组长度哦~不过呢,允许最多把 k 个0翻成1,是不是很有意思?快来看看怎么解决吧~

示例

  • 输入:nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2

    • 输出:6
    • 解释:把前两个0翻成1,就得到超长的1序列啦,长度直接到6~
  • 输入:nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], k = 3

    • 输出:10
    • 解释:翻三个0之后,连续1的长度直接干到10,爽不爽~

解法分析:滑动窗口法

核心思路

这里咱们用滑动窗口(双指针)来解决,思路超简单:维护一个窗口,保证里面最多有 k 个0。窗口越大,能翻成的连续1就越长~具体怎么操作呢?往下看~

代码实现

class Solution:
    def longestOnes(self, nums: List[int], k: int) -> int:
        l = ans = cnt = 0
        for i in range(len(nums)):
            # 统计窗口里有多少个0,0的话cnt+1,1的话不变
            cnt += nums[i] ^ 1
            # 如果0太多了(超过k个),就把左指针往右移
            while cnt > k:
                cnt -= nums[l] ^ 1
                l += 1
            # 随时更新最长连续1的长度
            ans = max(ans, i - l + 1)
        return ans

代码解析

  1. 初始化变量

    • l 是左指针,初始位置0,用来缩窗口的~
    • ans 存最长连续1的长度,初始为0,后面慢慢更新~
    • cnt 数窗口里有多少个0,初始也是0~
  2. 遍历数组

    • 右指针 i 从左到右走,每到一个位置,看看是不是0:
      • 是0的话,cnt += 1(用nums[i] ^ 1算,超方便~)
      • 是1的话,cnt 不变~
  3. 调整窗口

    • 如果cnt超过k了,说明窗口里0太多啦,得把左指针l右移:
      • 左指针位置的数如果是0,cnt -= 1
      • 左指针挪一步,窗口变小~
  4. 更新最长长度

    • 每次都算一下当前窗口长度i - l + 1,和之前的ans比,取大的那个~

关键技巧说明

  1. 位运算yyds:用nums[i] ^ 1判断是不是0,0 ^ 1=1(加1),1 ^ 1=0(不加),是不是超简洁~

  2. 滑动窗口怎么玩

    • 右指针疯狂扩展窗口,左指针看情况收缩,保证窗口里最多k个0~
    • 这样一来,窗口里的0都翻成1之后,不就是连续1嘛~
  3. 窗口长度计算i - l + 1就是当前窗口长度,因为左闭右闭区间呀~

示例详解

以输入nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2为例,咱们一步步看:

  1. 刚开始l=0cnt=0ans=0
  2. i=0,数是1,cnt还是0,窗口长度1,ans=1
  3. i=1,数是1,cnt还是0,窗口长度2,ans=2
  4. i=2,数是1,cnt还是0,窗口长度3,ans=3
  5. i=3,数是0,cnt=1,窗口长度4,ans=4
  6. i=4,数是0,cnt=2,窗口长度5,ans=5
  7. i=5,数是0,cnt=3(超过k=2啦!),这时候左指针开始挪:
    • 先挪到l=1cnt还是3(因为nums[0]是1)~
    • 再挪到l=2cnt还是3(nums[1]是1)~
    • 再挪到l=3nums[2]是1,cnt还是3~
    • 最后挪到l=4nums[3]是0,cnt=2,这时候窗口长度是5-4+1=2,但ans还是5~
  8. 后面继续走,到i=9的时候,窗口长度能到6,最终ans=6,符合示例~

总结

这个解法用滑动窗口超高效,时间复杂度O(n),空间复杂度O(1)~核心就是保持窗口里的0不超过k个,这样翻完就是连续1啦~宝子们学会了吗?遇到类似“最多改k个元素”的题,试试滑动窗口,超好用哦~