题目要求:给你一个正整数数组 arr ,请你计算所有可能的奇数长度子数组的和。
子数组 定义为原数组中的一个连续子序列。
请你返回 arr 中 所有奇数长度子数组的和 。
示例 1:
输入:arr = [1,4,2,5,3]
输出:58
解释:所有奇数长度子数组和它们的和为:
[1] = 1
[4] = 4
[2] = 2
[5] = 5
[3] = 3
[1,4,2] = 7
[4,2,5] = 11
[2,5,3] = 10
[1,4,2,5,3] = 15
我们将所有值求和得到 1 + 4 + 2 + 5 + 3 + 7 + 11 + 10 + 15 = 58
示例 2:
输入:arr = [1,2]
输出:3
解释:总共只有 2 个长度为奇数的子数组,[1] 和 [2]。它们的和为 3 。
示例 3:
输入:arr = [10,11,12]
输出:66
提示:
1 <= arr.length <= 100
1 <= arr[i] <= 1000
解法一:
思路简单的三次for循环,虽然复杂度较高,但容易理解,适合菜菜T-T.
首先第一层for循环是确定数组中第一个元素并循环;
第二层for循环是确定可以在该数后面跟的数字个数,奇数长度组合也就是1、3、5…范围的确定就是该数后的数组元素个数;
第三层for循环是对上面两层循环确定的数进行求和,需要注意起点(k = i)和范围(k <= i+j)。
附上我的代码:
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
int arrnum = arr.size();
int nums = 0;
for(int i=0; i<arrnum; i++)
{
for(int j=0; j<arrnum-i; j=j+2)
{
for(int k=i; k<=i+j; k++)
{
nums = nums + arr[k];
}
}
}
return nums;
}
};
这个是我第二天自己想出来的!!(当然也是在小赵老师的指导下)菜菜的快乐有点简单~ 开心~~
解法二: 优解:
遍历一遍所有的元素,然后查看这个元素会在多少个长度为奇数的数组中出现过。
分析:
因为要计算出数组(arr)每个数在各组合出现的次数,所以:
以某数(第 i 位,即 arr[ i ])为分界线,分为左右
其左边能产生的组合数为 left = i + 1;
右边能产生的组合数为 right = arr.size() - i
寻找长度为奇数的,需要是:
奇数 + 该数 + 奇数 或
偶数 + 该数 + 偶数
所以要分别寻找两边奇数和偶数组合数
left_even = (left + 1) / 2;(左边偶数个数字的选择方案)
right_even = (right + 1) / 2;
left_odd = left / 2;
right_odd = right / 2
所以,该数出现的组合数为
left_even * right_even + left_odd * right_odd
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
int res = 0;
for(int i = 0; i < arr.size(); i ++)
{
int left = i + 1,
right = arr.size() - i,
left_even = (left + 1) / 2,
right_even = (right + 1) / 2,
left_odd = left / 2,
right_odd = right / 2;
res += (left_even * right_even + left_odd * right_odd) * arr[i];
}
return res;
}
};
①
除法运算符 “ / ” :二元运算符,具有左结合性。参与运算的量均为整型时,结果为整型,舍去小数;如果运算量中有一个为实型,结果为双精度实型。
eg:
5/2=2,1/2=0
5/2.0=2.5
求余运算符 “ % ”:二元运算符,具有左结合性。参与运算的量均为整型。求余运算的结果等于两个数相除后的余数。
解法三:
用滑动窗口把每个情况都算出来
用滑动窗口函数 window 计算数组里长度为len的所有子数组值的总和
滑动窗口长度取值范围 例: 数组长度为5时,我们分别计算以1、3、5为长度的滑动窗口
代码如下:
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
int sum = 0;//计算总和
int size = arr.size();//数组长度
for (int len = 1; len <= size; len += 2) {//len滑动窗口长度
sum += window(arr,len);//将每次放回的和累加到一起
}
return sum;
}
//滑动窗口代码
int window(vector<int>& arr, int len) {
int i = 0;//左指针
int j = 0;//右指针
int sum = 0;//当前滑动窗口的和
int ssum = 0;//返回的总和
while (j < arr.size())
{
sum += arr[j];
if(j - i + 1 == len)
{//长度等于len长度时就计算总和,然后移动左指针并处理当前滑动窗口的和
ssum += sum;
sum -= arr[i];
i++;
}
j++;
}
return ssum;
}
};