leetcode1493. 删掉一个元素以后全为 1 的最长子数组
给你一个二进制数组 nums
,你需要从中删掉一个元素。
请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。
如果不存在这样的子数组,请返回 0 。
示例 1
输入:nums = [1,1,0,1]
输出:3
解释:删掉位置 2 的数后,[1,1,1] 包含 3 个 1 。
示例 2
输入:nums = [0,1,1,1,0,1,1,0,1]
输出:5
解释:删掉位置 4 的数字后,[0,1,1,1,1,1,0,1] 的最长全 1 子数组为 [1,1,1,1,1] 。
示例 3
输入:nums = [1,1,1]
输出:2
解释:你必须要删除一个元素。
示例 4
输入:nums = [1,1,0,0,1,1,1,0,1]
输出:4
示例 5
输入:nums = [0,0,0]
输出:0
提示:
1 <= nums.length <= 10^5
-
nums[i]
要么是0
要么是1
。
方法:记录0的索引位置
思路:
我们希望得到的是两个最长的全为1的子数组,中间只有1个0,这样删除之后,这两个全为1的数组的长度加在一起就为答案。由于数组是二进制的,只有1和0,那么我们需要找到0的位置,然后把每个0左右的全为1数组长度相加,找出最大值即可。
我们维护一个字典,键为0的索引,值为这个0前面的全为1的数组长度,如果连续两个0出现,那么第二个0位置对应的值为0,表示这个0前面没有1。同时维护一个数组zero,存放所有0的位置。
我们遍历这个整个nums数组,填写字典和zero数组。
然后我们遍历zero数组,zero[i]和zero[i+1]在字典中的值之和,即为zero[i]位置的0删除后,全为1的子数组长度。我们找到最大的即可。同时需要注意的是,对于最后一个zero,zero[i+1]不存在,因此需要在上面遍历nums结束后,在zero中加上位置n+1,表示末尾,这样最后一个0可以将它前面的以及后面的全为1的子数组加在一起。
还需要考虑的是,如果zero数组只有一个元素,那么说明就是末尾n+1,则整个数组不存在0,只有1,根据题意,必须删除一个元素,直接返回n-1。
- 遍历了1次nums,一次zero,时间复杂度O(2N),渐进时间复杂度为O(N)。
- 使用了一个字典和一个数组,空间复杂度为O(N)
代码:
class Solution:
def longestSubarray(self, nums: List[int]) -> int:
zero = []
#键为这个都为1的子数组结束后的0的位置,值为这个子数组的长度
leng_idx = dict()
n = len(nums)
#temp为当前遍历到的全为1的子数组的长度
temp = 0
ans = 0
for i in range(n):
if nums[i]:
temp += 1
else:
leng_idx[i] = temp
temp = 0
#保存0的位置
zero.append(i)
#保存最后一个子数组以及把末尾n+1当作0
leng_idx[i+1] = temp
zero.append(i+1)
#如果只有一个元素,说明没有0,返回n-1
if len(zero) == 1:
return n-1
else:
#遍历所有的0前后的数组长度之和,找到最长的
for i in range(len(zero)-1):
ans = max(ans,leng_idx[zero[i]]+leng_idx[zero[i+1]])
return ans
结果: