题目链接
题目描述
宝子们,给你们一个二进制数组 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就越长~具体怎么操作呢?往下看~
代码实现
python
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
代码解析
-
初始化变量:
l是左指针,初始位置0,用来缩窗口的~ans存最长连续1的长度,初始为0,后面慢慢更新~cnt数窗口里有多少个0,初始也是0~
-
遍历数组:
- 右指针
i从左到右走,每到一个位置,看看是不是0:- 是0的话,
cnt += 1(用nums[i] ^ 1算,超方便~) - 是1的话,
cnt不变~
- 是0的话,
- 右指针
-
调整窗口:
- 如果
cnt超过k了,说明窗口里0太多啦,得把左指针l右移:- 左指针位置的数如果是0,
cnt -= 1 - 左指针挪一步,窗口变小~
- 左指针位置的数如果是0,
- 如果
-
更新最长长度:
- 每次都算一下当前窗口长度
i - l + 1,和之前的ans比,取大的那个~
- 每次都算一下当前窗口长度
关键技巧说明
-
位运算yyds :用
nums[i] ^ 1判断是不是0,0 ^ 1=1(加1),1 ^ 1=0(不加),是不是超简洁~ -
滑动窗口怎么玩:
- 右指针疯狂扩展窗口,左指针看情况收缩,保证窗口里最多k个0~
- 这样一来,窗口里的0都翻成1之后,不就是连续1嘛~
-
窗口长度计算 :
i - l + 1就是当前窗口长度,因为左闭右闭区间呀~
示例详解
以输入nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2为例,咱们一步步看:
- 刚开始
l=0,cnt=0,ans=0~ i=0,数是1,cnt还是0,窗口长度1,ans=1~i=1,数是1,cnt还是0,窗口长度2,ans=2~i=2,数是1,cnt还是0,窗口长度3,ans=3~i=3,数是0,cnt=1,窗口长度4,ans=4~i=4,数是0,cnt=2,窗口长度5,ans=5~i=5,数是0,cnt=3(超过k=2啦!),这时候左指针开始挪:- 先挪到
l=1,cnt还是3(因为nums[0]是1)~ - 再挪到
l=2,cnt还是3(nums[1]是1)~ - 再挪到
l=3,nums[2]是1,cnt还是3~ - 最后挪到
l=4,nums[3]是0,cnt=2,这时候窗口长度是5-4+1=2,但ans还是5~
- 先挪到
- 后面继续走,到
i=9的时候,窗口长度能到6,最终ans=6,符合示例~
总结
这个解法用滑动窗口超高效,时间复杂度O(n),空间复杂度O(1)~核心就是保持窗口里的0不超过k个,这样翻完就是连续1啦~宝子们学会了吗?遇到类似"最多改k个元素"的题,试试滑动窗口,超好用哦~