Medium
题目描述
给定一个整数数组 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^42 <= k <= 10^4
解题思路
推荐解法:前缀和 + 哈希表
这道题的关键洞察是:如果两个前缀和对 k 的余数相同,那么它们之间的子数组和一定能被 k 整除。
具体思路:
- 维护前缀和的模 k 余数
- 使用哈希表记录每个余数出现的次数
- 当遇到某个余数时,说明之前出现过相同余数的前缀和,它们之间的所有子数组都满足条件
需要注意的细节:
- 初始化时,余数 0 的计数为 1(表示空前缀)
- 处理负数余数:在某些语言中
-1 % 5 = -1,需要转换为正数(-1 + 5) % 5 = 4 - 每次遇到已存在的余数时,答案增加该余数之前出现的次数
时间复杂度 O(n),空间复杂度 O(min(n,k)),是最优解法。
其他解法:
- 暴力解法:枚举所有子数组,时间复杂度 O(n²),会超时
代码实现
class Solution {
public:
int subarraysDivByK(vector<int>& nums, int k) {
unordered_map<int, int> count;
count[0] = 1;
int sum = 0, result = 0;
for (int num : nums) {
sum += num;
int remainder = ((sum % k) + k) % k;
result += count[remainder];
count[remainder]++;
}
return result;
}
};
class Solution:
def subarraysDivByK(self, nums: List[int], k: int) -> int:
count = {0: 1}
prefix_sum = 0
result = 0
for num in nums:
prefix_sum += num
remainder = prefix_sum % k
result += count.get(remainder, 0)
count[remainder] = count.get(remainder, 0) + 1
return result
public class Solution {
public int SubarraysDivByK(int[] nums, int k) {
Dictionary<int, int> count = new Dictionary<int, int>();
count[0] = 1;
int sum = 0, result = 0;
foreach (int num in nums) {
sum += num;
int remainder = ((sum % k) + k) % k;
if (count.ContainsKey(remainder)) {
result += count[remainder];
count[remainder]++;
} else {
count[remainder] = 1;
}
}
return result;
}
}
var subarraysDivByK = function(nums, k) {
const count = new Map();
count.set(0, 1);
let sum = 0, result = 0;
for (const num of nums) {
sum += num;
let remainder = ((sum % k) + k) % k;
result += count.get(remainder) || 0;
count.set(remainder, (count.get(remainder) || 0) + 1);
}
return result;
};
复杂度分析
| 复杂度类型 | 大小 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(min(n, k)) |
说明:
- 时间复杂度:遍历数组一次,每次哈希表操作为 O(1)
- 空间复杂度:哈希表最多存储 min(n, k) 个不同的余数
相关题目
. Subarray Sum Equals K (Medium)
. Make Sum Divisible by P (Medium)
. Count Number of Bad Pairs (Medium)
. Count of Interesting Subarrays (Medium)