LeetCode 1588 所有奇数长度子数组的和

题目要求:给你一个正整数数组 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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值