Related topics :
Title description
Give you an integer array nums and an integer k.
If there are exactly k odd numbers in a continuous sub-array, we consider this sub-array to be a "beautiful sub-array".
Please return the number of "beautiful sub-arrays" in this array.
示例 1:
输入:nums = [1,1,2,1,1], k = 3
输出:2
解释:包含 3 个奇数的子数组是 [1,1,2,1] 和 [1,2,1,1] 。
示例 2:
输入:nums = [2,4,6], k = 1
输出:0
解释:数列中不包含任何奇数,所以不存在优美子数组。
示例 3:
输入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
输出:16
prompt:
1 <= nums.length <= 50000
1 <= nums[i] <= 10^5
1 <= k <= nums.length
Source: LeetCode
Link: https://leetcode-cn.com/problems/count-number-of-nice-subarrays
Ideas :
1.题目要我们找的是有多少个区间包含,k个奇数,我们把前j个区间的奇
数用前缀和保存起来,若区间[i~j]中有k奇数,即可表示为sum[j]-sum[i-1]=k,
这么一来是不是就跟“和为k的子数组”一样了;
2.直接用前缀和的做法时间复杂度是O(n)2,如果想要O(n)的时间复杂度,
怎么做呢?用前缀和的做法是这样的
int res=0;
for(int j=1;j<=length;j++){
for(int i=1;i<=j;i++){
if(sum[j]-sum[i-1]==k){
res++;
}
}
}
我们要从以i为右边界里找,有多少个以j为左边界的区间使得sum[j]-
sum[i-1]=k,想减掉i这重循环,要从(sum[j]-sum[i-1]=k)这个
等式来看,sum[i-1]=sum[j]-k,这样改等式可以变成(sum[j]-
(sum[j]-k)=k)这样我们就可以把i“变没”,我们只需要找到以j为右
边间的区间里,sum[j]-k出现的次数然后相加,这里可以用数组也可以
用Hashmap;
3.这里要注意的一点是hashmap或者数组要有初始值hashmap.put(0, 1),
count[0]=1,这是因为要保持哈希表的定义, key 是当前位置之前的所
有元素的和(依然是前缀和),value 是对应的个数。在遍历开始之前,
当前位置之前的所有元素为空,可以认为和是 0,对应的个数就为 1
(来自liweiwei大佬)
Code :
public int numberOfSubarrays(int[] nums, int k) {
int []sum=new int[nums.length+1];//前i个数字中,奇数的个数
//[1,2,3,4,5,6,7,8]
//[1,1,2,2,3,3,4,4]
int []count=new int [100000];
int res=0;
count[0]=1;
for(int i=1;i<=nums.length;i++){
sum[i]+=sum[i-1];
//判断是否为奇数
if(nums[i-1]%2!=0)
sum[i]+=1;
count[sum[i]]++;
//奇数个数开始大于K的时候才能开始,要不然sum[i]-k小于零会越界
if(sum[i]>=k){
res+=count[sum[i]-k];
}
}
return res;
}
}