【算法系列】(前缀和+哈希)和为K的子数组个数

题目:和为K的子数组

link

题解

首先明确题目中给出的数组是整数数组,包含负数/正数/0,其次数组是 无序 的,再然后需要找的是和为K的 子数组 ,子数组是 连续 的原数组片段且 非空

解法1:暴力枚举

依次固定子数组左端的边界,再枚举子数组右端的边界,时间复杂度O(N^2),空间复杂度O(1)
暴力枚举图示

代码

class Solution(object):
    def subarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        ret = 0
        size = len(nums)
        for i in range(0, size):
            count = 0
            for j in range(i, size):
                count += nums[j]
                ret = ret + 1 if count == k else ret
        return ret

暴力枚举的方法,我们计算一个子数组的和都是遍历子数组的方式取计算,或许可以换个方式??
计算方法解析图
如图中,第二种计算方法就让我们想到了前缀和去计算sumBlue-sumOrange。

解法2:利用前缀和

计算出数组的前缀和,当计算到i位置的前缀和时,向前寻找等于preSum[i]-k的前缀和
特殊处理:在前缀和数组前多引入一个0处理边界值问题

代码

class Solution(object):
    def subarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        ret = 0
        preSum = []
        preSum.append(0)
        count = 0
        for e in nums:
            count += e
            for num in preSum:
                ret = ret + 1 if count - num == k else ret
            preSum.append(count)
        return ret 

搞什么???时间复杂度还是O(N^2),而且空间复杂度还变为O(N)了
稍安勿躁!!!
我们会发现,我们在走到某个位置时会向前会找某个特定的值,我们寻找的方式是遍历,那岂不是浪费了查询高手哈希表,所以我们结合一下哈希,改良一下代码!!!

代码优化

class Solution(object):
    def subarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        # 前缀和+哈希优化
        ret = 0
        preSum = list()
        hash = dict()
        preSum.append(0)
        hash[0] = 1
        count = 0
        for e in nums:
            count += e
            res = hash.get(count - k)
            if res is not None:
                ret += res
            if count in hash:
                hash[count] += 1
            else:
                hash[count] = 1
        return ret

小小总结:前缀和是用来快速得到某个连续区间的和(也不一定是和,可能是乘积或其他),付出的代价是空间,必须存储下前缀和,典型的用空间换时间

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值