Approach 1
This is a straightforward approach and the interviewer probably expects you to discuss this approach. Approach 2 has some observational maths involved which makes the time complexity better. The idea here is to preprocess the array and store the prefix sum for each index (preSum[i] = sum of arr[0] to arr[i]). Then, iterate through the prefix sum array and if we find preSum[j] - preSum[i] to be divisible by k, that means we have found a subarray.
public class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
if (nums == null || nums.length == 0) return false;
int[] preSum = new int[nums.length+1];
for (int i = 1; i <= nums.length; i++) {
preSum[i] = preSum[i-1] + nums[i-1];
}
for (int i = 0; i < nums.length; i++) {
for (int j = i+2; j <= nums.length; j++) {
if (k == 0) {
if (preSum[j] - preSum[i] == 0) {
return true;
}
} else if ((preSum[j] - preSum[i]) % k == 0) {
return true;
}
}
}
return false;
}
}
Time complexity: O(n^2)
Space complexity: O(n) or O(1) if you store prefix sum in the input array itseld
Approach 2
Let’s say he have two number a and b where a%k == b%k
. This means that (a-b)%k == 0
. This is because:
Let a = p*k + r
b = q*k + r
Note that a%k = b%d = r
a - b = (p-q)%k
So (a-b)%k = 0
We will use this idea to solve the question. Let’s store (prefix sum)%k for each index instead of the prefix sum itself. Now, if for some index i, preSum[i]%k = X
and then for another index j, preSum[j]%k
= X. By the above property, (preSum[j]-preSum[i])%k = 0
. This means that the subarray i+1..j is divisible by k.
Code:
bool checkSubarraySum(vector<int>& nums, int k) {
int preSum = 0;
unordered_map<int, int> vis;
vis[0] = -1;
for (int i=0; i<nums.size(); i++) {
preSum += nums[i];
if (k!=0) preSum %= k;
if (vis.find(preSum) != vis.end()) {
if (i-vis[preSum]>1)
return true;
} else {
vis[preSum] = i;
}
}
return false;
}
Time complexity: O(n)
Space complexity: O(1)