题目描述
给定一个整数数组 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 <= A.length <= 30000
-10000 <= A[i] <= 10000
2 <= K <= 10000
这是昨天的【每日一题】,当时没想出来,允悲,明明是一道很简单的题,但是窗户纸没捅破就死活想不出来。
算法思路
本来这种题是可以用暴力方法破解的,但是在力扣里大部分的暴力破解都会被检测例子制裁。
class Solution:
def subarraysDivByK(self, A, K: int) -> int:
n=0
res=0
ls=[0]
for i in A:
n+=i
ls.append(n)
for i in range(1,len(ls)):
for j in range(i):
if (ls[i]-ls[j])%K==0:res+=1
return res
以上是最暴力最无脑的方法,检查所有的子数组可能性,要说有什么可取之处,就是使用ls
保存了所有从0-i
的数组和,然后通过减法得到i-j
的子数组和。
class Solution:
def subarraysDivByK(self, A, K: int) -> int:
n=0
res=0
ls={0:1}
for i in A:
n+=i
for j in ls.keys():
if (n-j)%K==0:
res+=ls[j]
ls[n]=ls.get(n,0)+1
return res
以上依然是暴力循环,但是又做了一点小优化,虽然没啥用就是了。
PERFECT
但其实这道题的技巧在于!!!(n-j)%K==0
实际上等价于n%K==j%K
,所以所有的数组和都可以化归到K以内的值,然后保存出现的频率即可。
class Solution:
def subarraysDivByK(self, A, K: int) -> int:
n=0
res=0
ls={0:1}
for i in A:
n+=i
tp=n%K
if tp in ls:
res+=ls[tp]
ls[tp] = ls.get(tp, 0) + 1
return res
执行用时 :392 ms, 在所有 Python3 提交中击败了50.00%的用户
内存消耗 :17.7 MB, 在所有 Python3 提交中击败了100.00%的用户
语言表述不透彻,但是有认真思考过的人应该可以看懂算法。