🧠
Prefix Sum + Hash Map (Optimal)
💡 This approach uses prefix sums and a hash map to count subarrays efficiently by tracking cumulative sums and their frequencies.
Intuition
Keep track of cumulative sums and use a hash map to find how many previous sums equal current_sum - k, which indicates subarrays summing to k.
Algorithm
- Initialize a hash map with {0:1} to count prefix sums.
- Iterate through nums, accumulating sum.
- Check if (current_sum - k) exists in map; if yes, add its count to result.
- Update map with current_sum count.
💡 The key insight is that subarray sums can be found by differences of prefix sums, and the hash map tracks how often each prefix sum occurs.
def subarraySum(nums, k):
count = 0
prefix_sum = 0
prefix_counts = {0: 1}
for num in nums:
prefix_sum += num
if prefix_sum - k in prefix_counts:
count += prefix_counts[prefix_sum - k]
prefix_counts[prefix_sum] = prefix_counts.get(prefix_sum, 0) + 1
return count
# Driver code
if __name__ == '__main__':
print(subarraySum([1,1,1], 2)) # Output: 2
Line Notes
count = 0Initialize count of valid subarrays found so far
prefix_sum = 0Running total of elements seen so far to form prefix sums
prefix_counts = {0: 1}Map to store counts of prefix sums; 0 sum occurs once initially to handle subarrays starting at index 0
for num in nums:Iterate over each element in the array
prefix_sum += numUpdate running prefix sum with current element
if prefix_sum - k in prefix_counts:Check if a prefix sum exists that forms a subarray summing to k
count += prefix_counts[prefix_sum - k]Add number of such prefix sums to count, representing valid subarrays ending here
prefix_counts[prefix_sum] = prefix_counts.get(prefix_sum, 0) + 1Update count of current prefix sum in the map
import java.util.HashMap;
public class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0, prefix_sum = 0;
HashMap<Integer, Integer> prefix_counts = new HashMap<>();
prefix_counts.put(0, 1);
for (int num : nums) {
prefix_sum += num;
if (prefix_counts.containsKey(prefix_sum - k)) {
count += prefix_counts.get(prefix_sum - k);
}
prefix_counts.put(prefix_sum, prefix_counts.getOrDefault(prefix_sum, 0) + 1);
}
return count;
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.subarraySum(new int[]{1,1,1}, 2)); // Output: 2
}
}
Line Notes
int count = 0, prefix_sum = 0;Initialize count and running prefix sum
HashMap<Integer, Integer> prefix_counts = new HashMap<>();Map to store prefix sum frequencies
prefix_counts.put(0, 1);Prefix sum 0 occurs once initially to handle subarrays starting at index 0
for (int num : nums)Iterate over array elements
prefix_sum += num;Update running prefix sum with current element
if (prefix_counts.containsKey(prefix_sum - k))Check if complement prefix sum exists indicating valid subarray
count += prefix_counts.get(prefix_sum - k);Add frequency of complement prefix sum to count
prefix_counts.put(prefix_sum, prefix_counts.getOrDefault(prefix_sum, 0) + 1);Update frequency of current prefix sum
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
int subarraySum(vector<int>& nums, int k) {
int count = 0, prefix_sum = 0;
unordered_map<int, int> prefix_counts;
prefix_counts[0] = 1;
for (int num : nums) {
prefix_sum += num;
if (prefix_counts.find(prefix_sum - k) != prefix_counts.end()) {
count += prefix_counts[prefix_sum - k];
}
prefix_counts[prefix_sum]++;
}
return count;
}
int main() {
vector<int> nums = {1,1,1};
cout << subarraySum(nums, 2) << endl; // Output: 2
return 0;
}
Line Notes
int count = 0, prefix_sum = 0;Initialize count and running prefix sum
unordered_map<int, int> prefix_counts;Hash map to store prefix sum counts
prefix_counts[0] = 1;Prefix sum 0 occurs once initially to handle subarrays starting at index 0
for (int num : nums)Iterate over each element
prefix_sum += num;Update running prefix sum with current element
if (prefix_counts.find(prefix_sum - k) != prefix_counts.end())Check if complement prefix sum exists indicating valid subarray
count += prefix_counts[prefix_sum - k];Add frequency of complement prefix sum to count
prefix_counts[prefix_sum]++;Increment count of current prefix sum
function subarraySum(nums, k) {
let count = 0, prefix_sum = 0;
const prefix_counts = new Map();
prefix_counts.set(0, 1);
for (const num of nums) {
prefix_sum += num;
if (prefix_counts.has(prefix_sum - k)) {
count += prefix_counts.get(prefix_sum - k);
}
prefix_counts.set(prefix_sum, (prefix_counts.get(prefix_sum) || 0) + 1);
}
return count;
}
// Test
console.log(subarraySum([1,1,1], 2)); // Output: 2
Line Notes
let count = 0, prefix_sum = 0;Initialize count and running prefix sum
const prefix_counts = new Map();Map to store prefix sum frequencies
prefix_counts.set(0, 1);Prefix sum 0 occurs once initially to handle subarrays starting at index 0
for (const num of nums)Iterate over array elements
prefix_sum += num;Update running prefix sum with current element
if (prefix_counts.has(prefix_sum - k))Check if complement prefix sum exists indicating valid subarray
count += prefix_counts.get(prefix_sum - k);Add frequency of complement prefix sum to count
prefix_counts.set(prefix_sum, (prefix_counts.get(prefix_sum) || 0) + 1);Update frequency of current prefix sum
Single pass through array with constant time hash map operations, total O(n).
💡 For n=100,000 this means about 100,000 operations, which is efficient and scalable.
Interview Verdict: Accepted
This is the optimal approach and the one to implement in interviews for efficiency.