一.题目描述
给你一个二元数组 nums ,和一个整数 goal ,请你统计并返回有多少个和为 goal 的 非空 子数组。子数组 是数组的一段连续部分。
示例 1:
输入:nums = [1,0,1,0,1], goal = 2
输出:4
解释:
有 4 个满足题目要求的子数组:[1,0,1]、[1,0,1,0]、[0,1,0,1]、[1,0,1]
示例 2:
输入:nums = [0,0,0,0,0], goal = 0
输出:15
提示:
- 1 <= nums.length <= 3 * 104
- nums[i] 不是 0 就是 1
- 0 <= goal <= nums.length
二.思路
求区间大于或者小于某个值并不困难,但是要解区间恰好等于某个值,那该如何求解呢?
我们不妨先假设:
A = A= A= 区间不大于于goal的总数量
B = B= B= 区间不大于于(goal-1)的总数量。
这样区间恰好等于goal的总数量: C = A − B C=A -B C=A−B
那这道题不就转换成求连续子数组不大于goal&(goal-1)的个数嘛 跟LeetCode.乘积小于K的子数组相似
三.源码
public static int numSubarraysWithSum(int[] nums, int goal) {
int a=getAns(nums,goal);//不大于goal的滑动窗口总数量
int b=getAns(nums,goal-1);//不大于(goal-1)的滑动窗口总数量
int c=a-b;//恰好等于goal的滑动窗口总数量
return c;
}
public static int getAns(int[] nums,int goal){//求不大于goal的滑动窗口
int left=0;
int len=nums.length;
int ans=0;
int cnt=0;
for(int right=0;right<len;right++){
cnt+=nums[right];
while(cnt>goal&&left<=right){
cnt-=nums[left];
left++;
}
ans+=right-left+1;
}
return ans;
}