力扣Leetcode第1588题,所有奇数长度子数组的和的Python解法

Description

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

Codes

class Solution(object):
    def sumOddLengthSubarrays(self, arr):
        """
        :type arr: List[int]
        :rtype: int
        """
        leng = len(arr)
        tot = 0

        for i in range(leng):
            left_odd = (i+1)//2
            left_even = i//2 + 1
            right_odd = (leng-i)//2
            right_even = (leng-i+1)//2
            tot += (left_odd * right_odd + left_even * right_even) * arr[i]

        return tot

思路

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;

下面的关键就是,如何计算一个数字在多少个奇数长度的数组中出现过?

对于2来说,它可以在它前面选择0,1,2 个数字,选0个即为不选,选1个即为[4,2] ,选2个即为 [1,4,2]
那么每一个数字,在左边选一共有left = i+1 种选择(i为数组下标)
对于2来说,它可以在它后面选择0,1,2个数字,选0即为不选,选1个即为[2,5],选2个即为[2,5,3]
那么每一个数字,在右边选一共有 right = n-i 种选择(n为数组长度)
如果在前面选择了偶数个数字,那么在后面,也必须选择偶数个数字,这样加上它自身,才构成奇数长度的数组;

如果在前面选择了奇数个数字,那么在后面,也必须选择奇数个数字,这样加上它自身,才构成奇数长度的数组;

数字前面共有 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 个奇数长度的数组中出现过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值