python-leetcode 10.和为K的子数组

题目:

给你一个整数数组nums和一个整数k,请你统计并返回该数组中和为k的子数组的个数

子数组是数组中元素的连续非空序列

方法一:暴力枚举法

枚举nums的所有子数组,统计其中和为k的子数组个数。

考虑以i结尾和为k的连续子数组的个数,统计符合条件的下标j的个数,其中0<=j<=i,且这个子数组的和为k。可以枚举[0,,,i]里所有的下标j来判断是否符合条件。

class Solution(object):
    def subarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        count=0  #记录和为k的子数组的个数,初始值为0
        for start in range(len(nums)): #遍历数组中的每一个元素作为子数组的起始位置
            sum=0  #表示从start到当前end索引位置的子数组的和
            for end in range(start,-1,-1): #遍历从start到0的所有索引
                sum+=nums[end]
                if sum==k:  #检查子数组的是否等于目标值k
                    count+=1
        return count  #返回和为k的子数组的数目


        

时间复杂度:O(n2)其中 n 为数组的长度。枚举子数组开头和结尾需要 O(n2) 的时间,其中求和需要 O(1) 的时间复杂度,因此总时间复杂度为 O(n2)。

空间复杂度:O(1)只需要常数空间存放若干变量

测试可以通过,但是提交会超过时间限制

方法二:前缀和+哈希表优化

可以使用前缀和和数组进一步优化方法一。定义前缀和数组pre使得pre[i]为nums[0],nums[i]中所有数的和,则pre[i]可以从pre[i-1]得到,即pre[i]=pre[i-1]+nums[i]

那么[j,,i]这个子数组的和为k,这个条件可以转换为pre[i]-pre[j-1]=k.简单移项可得到符合条件的下标j,需要满足pre[j-1]==pre[i]-k。所以可以考虑以i结尾的和为k的连续子数组个数时只要统计有多少个前缀和为pre[i]-k的pre[j]即可。

建立哈希表mp,以前缀和pre[i]为键,出现的次数为对应的值,记录pre[i]出现的次数,从左到右边更新mp边计算答案,那么以i结尾的答案mp[pre[i]-k]即可在O(1)时间内得到,最后的答案即为所有下标结尾和为k的子数组个数之和。

class Solution(object):
    def subarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        count=0 #初始化和为k的数组的数量
        sum=0 #初始化当前子数组的和
        map={0:1} #字典,记录前缀和出现的次数,考虑了空数组的情况
        for num in nums:
            sum +=num  #对于每个元素,更新当前子数组的和
            if sum-k in map:  #sum-k存在,意味着之前有一个子数组的和为sum -k,而当前的和为 sum,因此这两个子数组的和加起来就是 k
                count +=map[sum-k]#如果sum-k在map中出现过,表示从某些位置到当前元素子数组和为k
            map[sum]=map.get(sum,0)+1 #更新字典 map 中当前和 sum 的计数
                #map.get(sum,0)的作用是,如果字典中没有键sum,则返回默认值 0,否则返回当前sum的计数然后将计数加 1
        return count

时间复杂度:O(n)其中 n 为数组的长度。我们遍历数组的时间复杂度为 O(n),中间利用哈希表查询删除的复杂度均为 O(1),因此总时间复杂度为 O(n)

空间复杂度:O(n)其中 n 为数组的长度。哈希表在最坏情况下可能有 n 个不同的键值,因此需要 O(n) 的空间复杂度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值