Given an integer array nums
and an integer k
, determine if the array contains a continuous subarray of at least size two whose elements sum up to a multiple of k
(i.e., the sum is n * k
for some integer n
where n >= 1
). Return true
if such a subarray exists, otherwise return false
.
nums
).k
to be zero; in this case, look for a subarray whose sum is zero.Constraints:
nums.length
<= 105nums[i]
<= 109k
<= 231 - 1
At first glance, it seems we need to check all possible subarrays of length at least two and see if their sum is a multiple of k
. However, this brute-force approach would be very slow for large arrays, since there are O(N2) subarrays.
To optimize, we can remember that the sum of a subarray from index i
to j
can be computed as prefixSum[j+1] - prefixSum[i]
. If we want this difference to be a multiple of k
, then (prefixSum[j+1] - prefixSum[i]) % k == 0
, which means prefixSum[j+1] % k == prefixSum[i] % k
.
This insight allows us to use a hash map to quickly check if we've seen the same remainder before, and if so, whether the subarray is at least length two.
i
, compute prefixSum % k
(if k != 0
).
k == 0
, then just use the running sum (since we want the sum itself to be zero).k
.true
. If we finish the loop without finding one, return false
.
We use a hash map for O(1) lookups of previously seen remainders, making the solution efficient.
Example: nums = [23, 2, 4, 6, 7]
, k = 6
prefixSum = 0
, modMap = {0: -1}
.prefixSum = 23
, remainder = 23 % 6 = 5
prefixSum = 25
, remainder = 25 % 6 = 1
prefixSum = 29
, remainder = 29 % 6 = 5
This demonstrates how the hash map allows us to find a valid subarray efficiently.
The optimized approach is efficient enough for large input sizes.
The key insight is to use prefix sums and modular arithmetic to reduce the problem to checking for repeated remainders. By remembering the first index where each remainder is seen, we can quickly determine if a valid subarray exists. This approach is both elegant and efficient, allowing us to solve the problem in linear time with minimal extra space.
class Solution:
def checkSubarraySum(self, nums, k):
mod_map = {0: -1}
prefix_sum = 0
for i, num in enumerate(nums):
prefix_sum += num
remainder = prefix_sum if k == 0 else prefix_sum % k
if remainder in mod_map:
if i - mod_map[remainder] > 1:
return True
else:
mod_map[remainder] = i
return False
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
unordered_map<int, int> mod_map;
mod_map[0] = -1;
int prefix_sum = 0;
for (int i = 0; i < nums.size(); ++i) {
prefix_sum += nums[i];
int remainder = (k == 0) ? prefix_sum : prefix_sum % k;
if (mod_map.count(remainder)) {
if (i - mod_map[remainder] > 1) return true;
} else {
mod_map[remainder] = i;
}
}
return false;
}
};
class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
Map<Integer, Integer> modMap = new HashMap<>();
modMap.put(0, -1);
int prefixSum = 0;
for (int i = 0; i < nums.length; i++) {
prefixSum += nums[i];
int remainder = (k == 0) ? prefixSum : prefixSum % k;
if (modMap.containsKey(remainder)) {
if (i - modMap.get(remainder) > 1) {
return true;
}
} else {
modMap.put(remainder, i);
}
}
return false;
}
}
var checkSubarraySum = function(nums, k) {
const modMap = new Map();
modMap.set(0, -1);
let prefixSum = 0;
for (let i = 0; i < nums.length; i++) {
prefixSum += nums[i];
let remainder = (k === 0) ? prefixSum : prefixSum % k;
if (modMap.has(remainder)) {
if (i - modMap.get(remainder) > 1) {
return true;
}
} else {
modMap.set(remainder, i);
}
}
return false;
};