方法一: 前缀和
思路:
- 计算出前n-1项的总和 再加上第n项本身,就是第n项的总和
- 不会为空,所以长度>=1,所以从1开始
- 奇数长度,所以每次最大长度+2,就可以保证一直是奇数长度
- 第n个数=前n项和-前n-1项和 推导
第n项到第n+x项之和=前x项之和-前n项之和
关键: 我们只需要知道,以每一个数为队头的,所有满足奇数长度的情况.
==> 暨: 遍历数组,以每一个数为队头,寻找所有情况,并将其累加
==>暨:求每一种情况下 长度区间内的累加和
==> 暨 :利用前缀和 使用
第n项到第n+x项之和=前x项之和-前n项之和
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
//方法一: 前缀和
//创建一个前缀和数组
std::vector<int>dp(arr.size()+1,0);
dp[0]=0;
//前缀和数组填充
for(int i=0;i<arr.size();i++)
{
dp[i+1]=dp[i]+arr[i];
}
//前缀数组ok
//核心思想:n到n+x项的和=前n+x项之和-前n项之和
int tatol=0;
/*len表示数组的长度*/
for(int len=1;len<=arr.size();len+=2)
{
for(int i=0;i+len-1<arr.size();i++)
{
//right 为arr数组对应的下标
int right=len+i-1;
tatol+=dp[right+1]-dp[i];
}
}
return tatol;
}
};
方法二:找规律
1 2 3 4 x 5 6 7 8
关键想法:
对于这组数,我们只需要知道每一个数字到底会使用几次就可以算出总值
int total=0;
for(int i=0;i<n;i++)
{
total+=dp[i]*dp[i]出现的次数
}
这个时候我们重点转变为如何计算出现的次数
数字出现的次数=组合数=左边满足奇数长度的情况*右边满足奇数的长度
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr)
{
/*方法2: 数学法: 核心 奇数+1+奇数=奇数
偶数+1+偶数=奇数
左边的个数*右边的个数=总共的排列数
*/
int total=0;
for(int i=0;i<arr.size();i++)
{
/*奇数情况*/
int Left1=(i+1)/2; //左边有多少中可能
int Right1=(arr.size()-i)/2;//右边有多少中可能
/*偶数情况*/
int Left2=i/2+1; //左边有多少中可能
//为什么要/2 ==>将左右两边的数字没两个划分为一组,这样就可以保证绝对不会为偶数长度
//暨 偶数+1+偶数=奇数
int Right2=(arr.size()-i-1)/2+1;//右边有多少中可能
total+=(Left1*Right1+Left2*Right2)*arr[i];
}
return total;
}
};