前缀和算法总结,Leetcode周赛最小平均差(Python实现)

首先为什么要用前缀和?前缀和的优势在哪里?

给定一个列表[a1,a2,a3,a4,a5,a6,a7,a8,a9,a10],如果我们要求前i个元素的和,一般怎么做? python中自带的api是不是就可以基本实现
比如我们像要求前5个数的和,如下所示:

a = [1,2,3,4,5,6,7,8,9]
print(sum(a[:5]))
>> 15

sum()函数其实就是帮我们做了一次数组遍历,其时间复杂度是O(n),这在平时计算一个这样简单的前i个数的和,时间复杂度可以勉强接受,但是在解决问题时,外面在嵌套一个循环呢?那整个算法的时间复杂度是不是就一下子上来了?这是非常不可取的,那么我们用什么方法将这个值简单计算前i个数优化到O(1)复杂度呢?前缀和,只需要读取某一个位置的值,就是O(1)复杂度啊!

a = [1,2,3,4,5,6,7,8,9]
l = len(a)
s = [0]*l
s[0] = a[0]
for i in range(1,l):
	s[i] = s[i-1]+a[i]
print(s)
print(s[4])

>>[1, 3, 6, 10, 15, 21, 28, 36, 45]
>>15

前缀和还有一个好处,就是如果你想求[1,2,3,4,5,6,7,8,9]中后面四个元素的和怎么办?
在常规的操作就是sum(a[5:]),但是前缀和就可以s[-1]-s[4]就ok了,美滋滋!

那么这周的周赛有一道题完美的诠释了前缀和的美妙!
最小平均差
在这里插入图片描述
在这里插入图片描述
以下就是我最先实现的一个暴力解法,不出意外完美超时了,样例能跑通80%:

class Solution:
    def minimumAverageDifference(self, nums: List[int]) -> int:
        if len(nums)==1:
            return 0
        res = 100
        index = 1000
        l = len(nums)
        sums = sum(nums)
        for i in range(l):
            c = sum(nums[:i+1])
            a = c//(i+1)
            if i==l-1:
                k = abs(a)
            else:
                b = (sums-c)//(l-i-1)
                k = abs(a-b)
            if k< res:
                res = k
                index = i
        return index

通过上面的讲解,应该知道这个代码的问题所在了吧,就是反复调用sum()函数,就大大增加了时间复杂度啊,跑通了才怪,O(n^2)的时间复杂度,是不是需要考虑优化

前缀和的写法,就将时间复杂度简化到了O(n)

class Solution:
    def minimumAverageDifference(self, nums: List[int]) -> int:
        # 使用前缀和
        l = len(nums)
        s = [0]*l
        s[0] = nums[0]
        for i in range(1,l):
            s[i]=s[i-1]+nums[i]
        if len(nums)==1:
            return 0
        res = 1000000 # 更地道的写法是float('inf')
        index = 1000000 # 可以写-1
        l = len(nums)
        for i in range(l):
            a = s[i]//(i+1)
            if i==l-1:
                k = abs(a)
            else:
                b = (s[-1]-s[i])//(l-i-1)
                k = abs(a-b)
            if k< res:
                res = k
                index = i
        return index

总结:如果你在解决一个问题,需要反复调用sum()这类本质上需要遍历数组的复杂度性质的api,考虑前缀和!考虑前缀和!考虑前缀和!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值