文巾解题1588. 所有奇数长度子数组的和

Posted UQI-LIUWJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文巾解题1588. 所有奇数长度子数组的和相关的知识,希望对你有一定的参考价值。

1 题目描述

 2 解题思路

2.1 直接求解

枚举子数组的长度和首位置

class Solution:
    def sumOddLengthSubarrays(self, arr: List[int]) -> int:
        l=len(arr)
        ret=0
        for i in range(1,l+1,2):
            for j in range(l-i+1):
                ret+=sum(arr[j:j+i])
        return(ret)

2.2 直接求解+前缀和

class Solution:
    def sumOddLengthSubarrays(self, arr: List[int]) -> int:
        l=len(arr)
        s=[0]
        for i in arr:
            s.append(s[-1]+i)
        ret=0
        for i in range(1,l+1,2):
            #子序列长度1~l,每次增长2
            for j in range(l-i+1):
                #子序列起始点,最大为l-i(此时的终点为l-i+i-1=l-1)
                ret+=s[i+j]-s[j]
        return(ret)

2.3 双指针

        首先把问题转化成,每个数存在在多少个奇数子数组中,也就是每个数重复了多少次。

        很容易发现数组的第一个数,重复的次数由总长决定。奇数的子数组有多少个呢,正好是(length + 1) // 2。

        那么前一个数和后一个数是否存在依赖关系呢?
        观察到,第一个数组成长度3、5、7等长度的子数组的时候,始终带着第二个数,但长度为1的时候没有第二个数出现。

        

        同样的,从第二个数往后面组成的子数组和第一个数没有关系。
也就是说,第二个数出现了第一个数出现的次数,但是少了第一个数出现、第二个数没出现的次数。而且第二个数还比第一个数多了第二个数出现、第一个数没出现的次数。上一个数出现的次数可以记录。
       

         那么上一个数出现,当前的数没出现有多少次呢?正好是一个递归思想,数组从0到i-1构成多少个包含i-1的子数组,就又是长度计算的。(根据对称性,这又等于从0到i-1构成多少个包含0的子数组)

        而当前的数出现,上一个数没出现,又正好是i到n-1构成多少个包含i的子数组,同样是长度计算的。

        于是我们知道以下信息:

  •         在数组1~n中,第一位出现(n+1)//2次
  •         当前位比上一位多 (n - i + 1) // 2 - (i + 1) // 2
  •         首尾对应位置出现次数相同(对称性)
class Solution:
    def sumOddLengthSubarrays(self, arr: List[int]) -> int:
        l=len(arr)

        begin, end  , ret, times = 0, n - 1, 0, (n+1) // 2
        while begin <= end:
            # 对称性,前后对称位置出现的次数一样
            if begin< end:
                ret += times * (arr[l] + arr[r])
            else:
                ret += times * arr[l]
            begin += 1
            end -= 1
            
            times += (l- begin + 1) // 2 
            '''
            下一个数比前一个数多的部分:
            后一个数构成的不带前一个数的奇数子数组的个数
            也即以下一个数为第一个数,剩余数组中奇数子数组个数
            '''
            
            times -= (begin + 1) // 2
            '''
            下一个数比前一个数少的部分:
            前一个数构成的不带后一个数的奇数子数组的个数
            也即第一个数为首个数,到l之前为止,这一个子数组中奇数子数组的个数
            '''
        return ret

以上是关于文巾解题1588. 所有奇数长度子数组的和的主要内容,如果未能解决你的问题,请参考以下文章

算法1588. 所有奇数长度子数组的和(多语言实现)

算法1588. 所有奇数长度子数组的和(多语言实现)

1588. 所有奇数长度子数组的和前缀和

[E前缀和] lc1588. 所有奇数长度子数组的和(前缀和+数学)

[E前缀和] lc1588. 所有奇数长度子数组的和(前缀和+数学)

LeetCode 1480. 一维数组的动态和 / 1588. 所有奇数长度子数组的和 / 528. 按权重随机选择(随机化)