🧠
Prefix Sum with Hash Map (Remainder Tracking)
💡 This approach uses prefix sums and modular arithmetic to reduce the problem to checking if the same remainder has appeared before, enabling O(n) time complexity.
Intuition
If the sum of elements from index 0 to i has remainder r when divided by k, and the sum from 0 to j (j > i) also has remainder r, then the subarray from i+1 to j sums to a multiple of k.
Algorithm
- Initialize a hash map to store remainder to earliest index mapping, starting with remainder 0 at index -1.
- Iterate through nums, accumulating prefix sums.
- Calculate current prefix sum modulo k (handle k=0 separately).
- If this remainder has been seen before and the subarray length is at least 2, return true.
- Otherwise, store the remainder with current index if not already stored.
- Return false if no qualifying subarray found.
💡 The key is to track remainders and their earliest occurrence to quickly identify valid subarrays without checking all pairs.
def checkSubarraySum(nums, k):
remainder_map = {0: -1}
total = 0
for i, num in enumerate(nums):
total += num
if k != 0:
total %= k
if total in remainder_map:
if i - remainder_map[total] > 1:
return True
else:
remainder_map[total] = i
return False
# Driver code
if __name__ == '__main__':
print(checkSubarraySum([23, 2, 4, 6, 7], 6)) # True
Line Notes
remainder_map = {0: -1}Initialize map with remainder 0 at index -1 to handle subarrays starting at index 0
total = 0Prefix sum accumulator
for i, num in enumerate(nums):Iterate over array with index
total += numAdd current element to prefix sum
if k != 0:Avoid modulo by zero
total %= kKeep prefix sum modulo k
if total in remainder_map:Check if this remainder was seen before
if i - remainder_map[total] > 1:Ensure subarray length at least 2
return TrueFound valid subarray
else: remainder_map[total] = iStore earliest index for this remainder
import java.util.HashMap;
public class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
HashMap<Integer, Integer> remainderMap = new HashMap<>();
remainderMap.put(0, -1);
int total = 0;
for (int i = 0; i < nums.length; i++) {
total += nums[i];
if (k != 0) {
total %= k;
}
if (remainderMap.containsKey(total)) {
if (i - remainderMap.get(total) > 1) {
return true;
}
} else {
remainderMap.put(total, i);
}
}
return false;
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.checkSubarraySum(new int[]{23, 2, 4, 6, 7}, 6)); // true
}
}
Line Notes
HashMap<Integer, Integer> remainderMap = new HashMap<>();Map remainder to earliest index
remainderMap.put(0, -1);Handle subarrays starting at index 0
int total = 0;Prefix sum accumulator
for (int i = 0; i < nums.length; i++) {Iterate over array
total += nums[i];Add current element
if (k != 0) { total %= k; }Modulo to keep remainder, avoid zero divisor
if (remainderMap.containsKey(total)) {Check if remainder seen before
if (i - remainderMap.get(total) > 1) {Check subarray length
return true;Found valid subarray
else { remainderMap.put(total, i); }Store earliest index for remainder
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
unordered_map<int, int> remainderMap;
remainderMap[0] = -1;
int total = 0;
for (int i = 0; i < nums.size(); i++) {
total += nums[i];
if (k != 0) total %= k;
if (remainderMap.find(total) != remainderMap.end()) {
if (i - remainderMap[total] > 1) return true;
} else {
remainderMap[total] = i;
}
}
return false;
}
};
int main() {
Solution sol;
vector<int> nums = {23, 2, 4, 6, 7};
cout << boolalpha << sol.checkSubarraySum(nums, 6) << endl; // true
return 0;
}
Line Notes
unordered_map<int, int> remainderMap;Map remainder to earliest index
remainderMap[0] = -1;Handle subarrays starting at index 0
int total = 0;Prefix sum accumulator
for (int i = 0; i < nums.size(); i++) {Iterate over array
total += nums[i];Add current element
if (k != 0) total %= k;Modulo to keep remainder, avoid zero divisor
if (remainderMap.find(total) != remainderMap.end()) {Check if remainder seen before
if (i - remainderMap[total] > 1) return true;Check subarray length
else { remainderMap[total] = i; }Store earliest index for remainder
function checkSubarraySum(nums, k) {
const remainderMap = new Map();
remainderMap.set(0, -1);
let total = 0;
for (let i = 0; i < nums.length; i++) {
total += nums[i];
if (k !== 0) total %= k;
if (remainderMap.has(total)) {
if (i - remainderMap.get(total) > 1) return true;
} else {
remainderMap.set(total, i);
}
}
return false;
}
// Test
console.log(checkSubarraySum([23, 2, 4, 6, 7], 6)); // true
Line Notes
const remainderMap = new Map();Map remainder to earliest index
remainderMap.set(0, -1);Handle subarrays starting at index 0
let total = 0;Prefix sum accumulator
for (let i = 0; i < nums.length; i++) {Iterate over array
total += nums[i];Add current element
if (k !== 0) total %= k;Modulo to keep remainder, avoid zero divisor
if (remainderMap.has(total)) {Check if remainder seen before
if (i - remainderMap.get(total) > 1) return true;Check subarray length
else { remainderMap.set(total, i); }Store earliest index for remainder
TimeO(n)
SpaceO(min(n, k))
Single pass through nums with constant time map operations results in O(n) time. Space depends on number of unique remainders, bounded by min(n, k).
💡 For n=100000, this approach can handle the input efficiently, unlike brute force.
Interview Verdict: Accepted
This is the optimal approach for this problem and is expected in interviews.