给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的(连续、非空) 子数组 的数目。
子数组 是数组的 连续 部分。
示例 1:
输入:nums = [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]
示例 2:
输入: nums = [5], k = 9
输出: 0
提示:
1 <= nums.length <= 3 * 10^4
-10^4 <= nums[i] <= 10^4
2 <= k <= 10^4
974. 和可被 K 整除的子数组 - 力扣(Leetcode)
思路:
定义前缀和数组 preSum,若是有子数组 nums[ i ], ..., nums[ j ] 的和为 k 的倍数,那么有
( preSum[ j ] - preSum[ i ] ) % k == 0, 即 preSum[ j ] % k == preSum[ i ]。
定义 map ,其中 key 为前缀和对k的取余,value 为 前缀和对 k 取余的次数。
有两个特殊情况需要考虑:
1. 负数取余 : ( v % k + k) %k
2. 当 preSum[ m ] 取余的结果为 0 时,证明子数组和 nums[ 0 ] + ... + nums[ m ] 为 k 的倍数
c++:
class Solution {
public:int subarraysDivByK(vector& nums, int k) {vector preSum(nums.size(), 0);map tarMap; // key 为前缀和对 k 的取余,value 为 这样的前缀和出现的次数int result = 0;tarMap[0] = 1;for(int i = 0; i < nums.size(); i++) {if(i == 0) {preSum[i] = nums[i];} else {preSum[i] = preSum[i-1] + nums[i];}int key = (preSum[i]%k+k) % k;if(tarMap.count(key)) {tarMap[key] += 1;} else {tarMap[key] = 1;}result += (tarMap[key] - 1);}return result;}
};
上一篇:阻塞式队列-生产者消费者模型