leetcode(26)_930_medium_和相同的二元子数组_python

和相同的二元子数组

题目描述:
给你一个二元数组 nums ,和一个整数 goal ,请你统计并返回有多少个和为 goal 的 非空 子数组。
子数组 是数组的一段连续部分。
示例 :
输入:nums = [1,0,1,0,1], goal = 2
输出:4
解释:
如下面黑体所示,有 4 个满足题目要求的子数组:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
提示:

  • 1 <= nums.length <= 3 * 104
  • nums[i] 不是 0 就是 1
  • 0 <= goal <= nums.length

解法一 前缀和

  1. 连续子区间的加和其实就是两个前缀和的差值,可以简单记为sum(num[left: right]) = prefix_sum(right) - prefix_sum(left)。因此我们遍历右端点,也就是对于right,我们需要知道前方与prefix_sum(right) - goal相等的前缀和有多少个,所以需要在遍历的同时记录各个前缀和的次数。
  2. 在具体进行迭代时,需要注意到没有元素时的前缀和是 0,所以应该先将前缀和更新到字典中。
代码
class Solution:
    def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:
        if goal > len(nums):
            return 0
        sum2cnt = {}
        prefix_sum, res = 0, 0
        for num in nums:
            sum2cnt[prefix_sum] = sum2cnt.get(prefix_sum, 0) + 1
            prefix_sum += num
            res += sum2cnt.get(prefix_sum - goal, 0)
        return res
      
测试结果

执行用时:228 ms, 在所有 Python3 提交中击败了 53.30% 的用户
内存消耗:18.3 MB, 在所有 Python3 提交中击败了 38.07% 的用户

解法二 滑动窗口

看到本题很容易想到滑动窗口的解法,但容易发现,对于某个右端点right,符合要求的左端点可能不止一个,所以左端点需要用两个变量来描述,[left1, left2)中的整数下标left均满足:sum(num[left: right + 1]) == goal。如此,每次在移动右端点的时候,也对左端点的区间进行更新,符合条件的窗口个数即为left2 - left1

代码
class Solution:
    def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:
        if goal > len(nums):
            return 0
        res = 0
        left1, sum1, left2, sum2 = 0, 0, 0, 0
        for right, item in enumerate(nums):
            sum1 += item
            while left1 <= right and sum1 > goal:
                sum1 -= nums[left1]
                left1 += 1
            sum2 += item
            while left2 <= right and sum2 >= goal:
                sum2 -= nums[left2]
                left2 += 1
            res += left2 - left1
        return res
 
测试结果

执行用时:252 ms, 在所有 Python3 提交中击败了 53.30% 的用户
内存消耗:15.5 MB, 在所有 Python3 提交中击败了 92.39% 的用户

说明

算法题来源:力扣(LeetCode)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值