给你一个正整数数组 arr ,请你计算所有可能的奇数长度子数组的和。
子数组定义为原数组中的一个连续子序列。请你返回 arr 中 所有奇数长度子数组的和 。
示例 1:
输入:arr = [1,4,2,5,3]
输出:58
解释:所有奇数长度子数组和它们的和为:
长度为1的子数组有[1],[4],[2],[5],[3] ,相加结果为15
长度为3的子数组有[1,4,2],[4,2,5],[2,5,3],相加的结果为7+11+10=28
长度为5的子数组有[1,4,2,5,3] ,相加的结果为15
我们将所有值求和得到 15+28+15 = 58
示例 2:
扫描二维码关注公众号,回复:
12980007 查看本文章
输入:arr = [1,2]
输出:3
解释:只有 2 个长度为1的子数组,[1] 和 [2]。它们的和为 3 。
算法1:按照题目的要求遍历相加即可
int sumOddLengthSubarrays(int* arr, int arrSize) //效率较低
{
int sum = 0;
for(int i=1;i<=arrSize;i+=2)//遍历所有奇数的子长度,如1,3,5,...,2n+1
{
for(int j=0;j<arrSize-i+1;j++)//每一组子数组
{
for(int k=0;k<i;k++)//把子数组的所有数字相加
{
sum += arr[j+k];
}
}
}
return sum;
}
算法2:计算每个数字出现的次数,然后相加
根据题意逐步计算子数组的和,发现每个数字都多次出现,多次计算,故思考能否直接计算每个数字的出现次数,思路如下:
1.任取数组下标为i(第i+1个)的元素
2.其左边可以取0~i个元素,共i+1种方案,其中(i+1)/2种为奇数,i/2+1种为偶数
3.右边可以取0~(n-i-1)个元素,共n-i种方案,其中(n-i)/2种为奇数,(n-i+1)/2种为偶数
4.合成子数组须满足条件:左边+本身+右边 = 奇数个,故左奇->右奇,左偶->右偶
5.所以arr[i]的出现次数为lOdd X rOdd + lEven X rEven,即左奇X右奇 + 左偶X右偶
int sumOddLengthSubarrays(int* arr, int arrSize)
{
int res = 0;
int lEven,lOdd,rEven,rOdd;//左偶数,左奇数,右偶数,右奇数
for(int i=0;i<arrSize;i++)
{
lOdd = (i+1)/2;
lEven = i/2 + 1;
rOdd = (arrSize-i)/2;
rEven = (arrSize-i+1)/2;
res += (lOdd*rOdd + lEven*rEven) * arr[i];
}
return res;
}