【leetcode-Python】-滑动窗口-1493. Longest Subarray of 1‘s After Deleting One Element

给定一个二进制数组,需要删除一个元素以得到最长的只包含1的非空子数组。文章通过滑动窗口算法详细解析解题过程,并提供了Python实现及优化思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

https://leetcode-cn.com/problems/longest-subarray-of-1s-after-deleting-one-element/

题目描述

给定二进制数组,需要从中删除一个元素。请你再删掉某个元素后得到的结果数组中,返回最长的且只包含1的非空子数组的长度。如果不存在这样的子数组,请返回0。

示例

输入:nums =  [1,1,0,1]

输出:3

删掉索引为2的数字0后,[1,1,1]包含3个1。

解题思路

此题和【leetcode-Python】-滑动窗口-424. Longest Repeating Character Replacement类似,可以等价于从nums中找到0的个数不超过1、包含1的数组最多的子串。我们仍可以按照传统滑动窗口模板来思考,维持窗口内子串的合法状态。右边界一直右移,直到窗口内子串不合法(窗口内0的个数大于1),右指针不懂,左指针开始右移。直到子串内0的个数小于等于1,子串恢复到合法状态,左指针不动,右指针继续右移......直到右指针到达nums末尾。

由于必须删除一个元素,因此删除元素后的子数组长度应该为最长合法窗口的长度减去1。

Python实现

class Solution:
    def longestSubarray(self, nums: List[int]) -> int:
        left,right = 0,0
        count = 0 #0的个数
        res = 0
        while(right < len(nums)):
            c = nums[right]
            right += 1
            if(c == 0):
                count += 1
            while(count > 1): #窗口内0的个数大于1
                d = nums[left]
                left += 1
                if(d == 0): #如果移出窗口的元素为0,给count减去1
                    count -= 1
            res = max(res,right-left-1) #在count<=1的条件下更新结果
        return res
        
        

进一步优化

由于找的是符合条件的最长子串,我们可以不维护窗口内子串的合法性,让滑动窗口要么扩张,要么平移(上面的常规滑动窗口算法更容易被记住并迁移,这种优化方法其实可以不记)。在这种方法下,窗口内的子串未必合法,但算法执行结束后子串的长度为至今满足题意的最长窗口长度。以nums = [0,1,1,1,0,1,1,0,1]为例说明这种更新方式:

右指针右移,直到窗口内0的个数超过1个。此时我们维护的删除一个元素后最长连续1的子串长度为4,子串为[0,1,1,1]。

此时窗口停止扩张,开始平移。左指针先移一位,右指针再移一位。经过滑动后窗口内0的个数为1,为合法子串,窗口长度为5。

右指针继续右移,新加入窗口的元素为1,符合条件,滑动窗口扩张。此时窗口内0的个数为1,为合法子串,窗口长度为6。

右指针继续右移,新加入窗口的元素为0,窗口内子串不再符合条件。

由于窗口内元素不再符合条件,滑动窗口开始平移(左边界移动一位后,右边界移动一位)。

窗口内子串中0个个数仍大于1,因此左指针右移一位。此时右指针已经到达数组终点,算法执行结束。此时[left,right)子串不合法,但是长度等于删除一个元素后最长连续1的子串长度,即为6。(因为滑动窗口扩张的条件是窗口内的子串合法,平移的条件是窗口内的子串不合法。滑动窗口平移到right到达字符串末尾时,如果窗口内的元素合法,那么当前窗口就是合法的最长子串。如果窗口内元素不合法,那么合法最长子串的长度就是当前窗口长度减去1(合法最长子串为扩张前的窗口)。left右移一位后当前窗口长度减去1,就和合法最长子串长度相同。因此我们最后可以直接返回right-left-1。减去的1表示子串中“删除的一个元素”)。

窗口内子串不满足条件时只平移不收缩是因为,收缩后得到的合法子串长度要么比收缩前得到的最长合法子串相等,要么比收缩前得到的最长合法子串短。因此收缩窗口不会给寻找“最长子串”带来任何帮助。

代码上的不同为:左边界一次只移动一位,将内层循环的while语句换为if语句。另外直接最后返回子串长度或对子串长度进行处理后的结果即可。

class Solution:
    def longestSubarray(self, nums: List[int]) -> int:
        left,right = 0,0
        count = 0 #0的个数
        res = 0
        while(right < len(nums)):
            c = nums[right]
            right += 1
            if(c == 0):
                count += 1
            if(count > 1): #窗口内0的个数大于1,此时我们平移滑动窗口
                d = nums[left]
                left += 1
                if(d == 0):
                    count -= 1
        return right-left -1
        
        

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值