You are given an integer array nums
and an integer k
. Your task is to find the number of non-empty subarrays that have a sum divisible by k
. A subarray is defined as a contiguous part of an array.
For example:
nums = [4, 5, 0, -2, -3, 1], k = 5
. The output should be 7 because the following subarrays have a sum divisible by 5: [4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]
.nums = [5], k = 9
. The output should be 0 because no subarray has a sum divisible by 9.Could you please provide an algorithm to solve this problem efficiently, considering the following constraints?
1 <= nums.length <= 3 * 10^4
-10^4 <= nums[i] <= 10^4
2 <= k <= 10^4
A naive approach would be to iterate through all possible subarrays and check if their sum is divisible by k
. This involves two nested loops to define the start and end indices of the subarrays.
Algorithm:
i
from 0 to n-1
.i
, iterate through all possible end indices j
from i
to n-1
.i
to j
.k
, increment the count.def subarraysDivByK_brute_force(nums, k):
count = 0
n = len(nums)
for i in range(n):
for j in range(i, n):
subarray_sum = sum(nums[i:j+1])
if subarray_sum % k == 0:
count += 1
return count
Time Complexity: O(n^2) due to the nested loops.
Space Complexity: O(1) as we are only using a constant amount of extra space.
We can optimize this using the concept of prefix sums and remainders. The key idea is that if two prefix sums have the same remainder when divided by k
, then the subarray between those two indices has a sum divisible by k
.
Algorithm:
prefix_sum
to 0.remainder_count
dictionary (or array) to store the count of each remainder.remainder_count[0]
to 1, as an empty subarray has a sum of 0, which is divisible by any k
.nums
array.prefix_sum
by adding the current element.prefix_sum
when divided by k
. Make sure the remainder is non-negative.remainder_count
for the current remainder.remainder_count
for the current remainder.def subarraysDivByK(nums, k):
remainder_count = {0: 1}
prefix_sum = 0
count = 0
for num in nums:
prefix_sum += num
remainder = prefix_sum % k
if remainder < 0:
remainder += k # Ensure remainder is non-negative
if remainder in remainder_count:
count += remainder_count[remainder]
remainder_count[remainder] += 1
else:
remainder_count[remainder] = 1
return count
Time Complexity: O(n) because we iterate through the array only once.
Space Complexity: O(k) because, in the worst case, the remainder_count
dictionary might store k
different remainders.