两个数组结果相减_leetcode974. 和可被 K 整除的子数组

leetcode974. 和可被 K 整除的子数组

给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续、非空)子数组的数目。

示例:

输入:A = [4,5,0,-2,-3,1], K = 5
输出:7
解释:
有 7 个子数组满足其元素之和可被 K = 5 整除:
[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]

提示:

  1. 1 <= A.length <= 30000
  2. -10000 <= A[i] <= 10000
  3. 2 <= K <= 10000

方法:前缀和+哈希表

思路:

本题与leetcode560题类似,

Andy Liu:leetcode560. 和为K的子数组(前缀和+哈希表)​zhuanlan.zhihu.com

只不过一个是求和为k的子数组,一个是求和可被k整除的子数组。方法是一样的。

首先我们考虑暴力法,维护dp数组表示前缀和,那么可知,i-j这个子数组的和为:dp[j] - dp[i-1],然后双层循环遍历,找到符合的情况计数即可,这样的时间复杂度是O(N^2),我们查看数据规模,发现肯定会超时。

我们同样使用哈希表来完成这个过程,首先使用pre变量来遍历数组存储到目前为止的前缀和,建立一个字典dp,它的键为余数,值为出现这个余数的个数。

dp[1]就表示为遍历到目前为止,前面出现的前缀和mod K得到的余数为1的位置数量。如果我们在遍历计算前缀和的时候,遇到了前缀和的余数为1,那么我们对这个位置,减去之前也出现余数为1的位置,这两个位置区间构成的子数组肯定可以被K整除,所以我们就对答案ans += dp[1],然后对dp[1] += 1更新。

我们还需要考虑到一种情况,如果一个数组,不是两个位置相减得到的子数组,而是从头开始到目前为止的子数组就满足条件,这个也需要考虑。那么容易知道,从头开始到目前位置的pre对于K的余数为0,也可以知道,每当pre%K == 0的时候,我们除了考虑与之前也为0的位置相减,还需要考虑一个从头开始的子数组也满足。所以我们只需要初始化对dp[0] = 1 即可。

代码:

class Solution:
    def subarraysDivByK(self, A: List[int], K: int) -> int:
        pre = 0
        dp = dict() #存放前缀和%K为0,1,2,3...的位置个数
        #初始化一个余数为0的子数组为1,这种情况是考虑到从头开始的到此处满足条件的数组的情况
        dp[0] = 1 
        ans = 0
        temp = 0
        n = len(A)
        for i in range(n):#遍历数组
            pre += A[i] #计算到此为止前缀和
            temp = pre % K #计算此处前缀和对于K的余数
            if temp in dp:
                ans += dp[temp] #dp[temp]表示这个余数temp的前面的前缀和出现的个数,现在的位置与之前同样是这个余数的位置相减得到的数组即为所求。
                dp[temp] += 1
            else: #dp中不存在这个余数的话,添加,数量记为1
                dp[temp] = 1
        return ans

结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值