leetcode560和为K的子数组、974和可被K整除的子数组

1、560和为K的子数组

leetcode560和为K的子数组、974和可被K整除的子数组_第1张图片
解题思路:由于数组长度很大,暴力O(n^2)的解法必定要超时,同时要找的是连续子数组,排序O(nlogn)肯定也不可以,此时应该想到利用hash表

如何优化呢?
首先,定义pre[i][0..i]里所有数的和,则有:pre[i]=pre[i−1]+nums[i]

同理,[j..i]这个子数组和为k这个条件可以转化为
pre[i]−pre[j−1]=k

所以,可以得到:pre[i]-k=pre[j−1]

所以求以i结尾的和为k的连续子数组个数可以转化为求有多少个前缀和为pre[i]−kpre[j]即可。

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

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        mp = {0:1}
        pre, res = 0, 0
        for i in nums:
            pre += i  # pre代表前缀和
            if pre-k in mp:  # 先计算mp[pre-k]
                res += mp[pre-k]
            if pre in mp:  # 再更新mp[pre],因为k可能为0
                mp[pre] += 1
            else:
                mp[pre] = 1
        return res   

2、974和可被K整除的子数组

leetcode560和为K的子数组、974和可被K整除的子数组_第2张图片
解题思路:和560题很相近,暴力法会超时,所以考虑前缀和+hash

具体实现为,pre记录前缀和与K的余数,如果premp中,说明有子数组的和是可以被K整除的,并且有mp[pre]个这样的子数组。
由于mp记录的是余数-余数出现次数,所以最终会求得所有能被K整除的子数组个数。

class Solution:
    def subarraysDivByK(self, A: List[int], K: int) -> int:
        mp = {0:1}
        pre, res = 0, 0
        for i in A:
            pre = (pre+i)%K
            if pre in mp:
                res += mp[pre]
                mp[pre] += 1
            else:
                mp[pre] = 1
        return res

你可能感兴趣的:(leetcode)