题目链接
题目描述
宝子们,给你们一个二进制数组 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个元素"的题,试试滑动窗口,超好用哦~