题目
给你一个整数数组 arr 。请你返回和为奇数的子数组数目。
由于答案可能会很大,请你将结果对 10^9 + 7 取余后返回。
示例1
输入:arr = [1,3,5]
输出:4
解释:所有的子数组为 [[1],[1,3],[1,3,5],[3],[3,5],[5]] 。
所有子数组的和为 [1,4,9,3,8,5].
奇数和包括 [1,9,3,5] ,所以答案为 4 。
示例2
输入:arr = [2,4,6]
输出:0
解释:所有子数组为 [[2],[2,4],[2,4,6],[4],[4,6],[6]] 。
所有子数组和为 [2,6,12,4,10,6] 。
所有子数组和都是偶数,所以答案为 0 。
解法
最开始解题时,想着就是如何搜索出各个子串,然后计算子串和,最后用一个set去记录。发现这个思路很直接,但是复杂度很高。
看了题解的解法,感觉是真的妙。官方题解给的思路是逆向求解,题目要求求解子串和为奇数的个数,根据一个数学规律:奇数+奇数=偶数;偶数+奇数=奇数。我们可以转换思路,在遍历到第i位时,我们求前i个数字和,如果这个和是偶数,我们只需要知道前j(j<i)个位置中有多少个和为奇数的子项,那剩下的j + 1到i位置的子项都一定是满足条件的子串数;同理,如果前i个数字和是奇数,我们只需要知道前面j个位置的子项和为偶数的数量。
class Solution {
public:
int numOfSubarrays(vector<int>& arr) {
int result = 0;
int odd = 0;
int even = 1;
int sum = 0;
for (int i = 0; i < arr.size(); ++i)
{
sum += arr[i];
if (sum % 2 == 0)
{
result = (result + odd) % 1000000007;
++even;
}
else
{
result = (result + even) % 1000000007;
++odd;
}
}
return result;
}
};