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