leetcode1588.所有奇数长度子数组的和

本文介绍了如何利用前缀和解决LeetCode上的1588题,即计算所有奇数长度子数组的和。文章通过分析暴力枚举和优化后的前缀和解题方法,展示了如何降低时间复杂度,从而更高效地解决问题。在C++代码实现中,通过初始化前缀和数组并迭代不同奇数长度的子数组,实现了快速求和的目标。
摘要由CSDN通过智能技术生成

一、题目(leetcode1588.所有奇数长度子数组的和

1.题目描述

给你一个正整数数组 arr ,请你计算所有可能的奇数长度子数组的和。

子数组 定义为原数组中的一个连续子序列。

请你返回 arr所有奇数长度子数组的和

提示:

  • 1 <= arr.length <= 100
  • 1 <= arr[i] <= 1000

示例 :

输入: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 。

2.基础框架

C/C++基础框架代码如下:

int numTrees(int n){
}

3.解题思路

  • 思路分析(个人思考过程,稍加繁杂)
  1. 题目目标是得到所有奇数长度的子数组相加的和。

  2. 从最短奇数长度为1的所有子数组加起来,然后再迭代下一次与第二短的奇数长度的所有子数组加起来,直到迭代完所有奇数长度的子数组,将所有奇数长度的子数组的和作为返回结果。

  3. 当奇数长度为length的子数组时,有n - (length - 1)个子数组,然后每个子数组开始为i,计算一个子数组内元素的和需要的时间为i+length - 1(因为i是length中的一部分,所以子数组的尾巴下标为length - 1)。当length长度为k时,那所需要的时间为(n - (k - 1)) * (i+ k - 1),抽象:

    (a - b) * (c + b) == ac + ab - bc + bbO(k^2),然后length以+=2的速度逐渐接近n,O(n/2 * k^2)。可将length视为n,所以总的时间复杂度应该是O(n/2 * n^2), O(n^3)。这里再看一下arr长度,如果采用O(n^3)的时间大概在10^6,貌似可以通过。

  4. 上面3采用的是暴力枚举的方式,如果这里采用前缀和,首先通过n阶初始化前缀和数组prefixSum,当length=k时,奇数长度为k的子数组相加和为:(n - (k - 1))个(prefixSum[length + i] - prefixSum[i])累加和,因为前缀和节省了子数组内部元素相加的时间开销,所以length为k时的时间复杂度为O(n - (k - 1))),总的时间复杂度为O(n/2 * [常量阶, n) ) ,大概在小于平方阶。

  • 实现代码:

      int sumOddLengthSubarrays(vector<int>& arr) {
          if (arr.empty()) return 0;
          vector<int> prefixSum(arr.size() + 1, 0);
          for (int i = 1; i < prefixSum.size(); i++)
              prefixSum[i] = arr[i - 1] + prefixSum[i - 1];	//初始化前缀和数组
      
          int sum = 0;
          for (int length = 1; length <= arr.size(); length += 2)
          {
              // cout << "length: " << length << endl;
              for (int i = 0; i <= int(arr.size() - length); i++)// i + length - 1 == arr.size() - 1
              {
                  sum += prefixSum[i + length] - prefixSum[i];
                  // cout << sum << " ";
              }
              cout << endl;
          }
          return sum;
      }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值