所有奇数长度子数组的和

所有奇数长度子数组的和

题目:给你一个正整数数组 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


解题思路

解法一

我们只需要枚举所有的奇数长度的子数组即可。在下面的代码中,i 用来枚举每个连续子数组的起点,gap为连续子数组的长度。accumulate用来计算起点是 i,长度为 gap 的子数组的和。时间复杂度是 O(n^3) 的。

代码展示

代码如下:

class Solution {
public:
    int sumOddLengthSubarrays(vector<int>& arr) {
        int sum=0,n=arr.size();
        for(int i=0;i<n;i++)
        {
            for(int gap=1;i+gap-1<n;gap+=2)
            {
                sum+=accumulate(arr.begin()+i,arr.begin()+i+gap,0);
            }
        }
        return sum;
    }
};

解法二

就是遍历一遍所有的元素,然后查看这个元素会在多少个长度为奇数的数组中出现过。

比如题目给出的第一个测试用例 [1, 4, 2, 5, 3] 中;
1 在 3 个长度为奇数的数组中出现过:[1], [1, 4, 2], [1, 4, 2, 5, 3];所以最终的和,要加上 1 * 3;
4 在 4 个长度为奇数的数组中出现过:[4], [4, 2, 5], [1, 4, 2], [1, 4, 2, 5, 3];所以最终和,要加上 4 * 4;
2 在 5 个长度为奇数的数组中出现过:[2], [2, 5, 3], [4, 2, 5], [1, 4, 2], [1, 4, 2, 5, 3];所以最终和,要加上 5 * 2;

下面的关键就是,如何计算一个数字在多少个奇数长度的数组中出现过?
对于一个数字,它所在的数组,可以在它前面再选择 0, 1, 2, … 个数字,一共有 left = i + 1 个选择;
可以在它后面再选择 0, 1, 2, … 个数字,一共有 right = n - i 个选择。
如果在前面选择了偶数个数字,那么在后面,也必须选择偶数个数字,这样加上它自身,才构成奇数长度的数组;
如果在前面选择了奇数个数字,那么在后面,也必须选择奇数个数字,这样加上它自身,才构成奇数长度的数组;
数字前面共有 left 个选择,其中偶数个数字的选择方案有 left_even = (left + 1) / 2 个,奇数个数字的选择方案有 left_odd = left / 2 个;
数字后面共有 right 个选择,其中偶数个数字的选择方案有 right_even = (right + 1) / 2 个,奇数个数字的选择方案有 right_odd = right / 2 个;
所以,每个数字一共在 left_even * right_even + left_odd * right_odd 个奇数长度的数组中出现过。

链接:https://leetcode-cn.com/problems/sum-of-all-odd-length-subarrays/solution/cong-on3-dao-on-de-jie-fa-by-liuyubobobo/

代码展示

代码如下:

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,left_odd=left/2,
                right_even=(right+1)/2,right_odd=right/2;
            res+=(left_even*right_even+left_odd*right_odd)*arr[i];
        }
        return res;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值