Find Subarrays with Sum K - C++ Algorithm Guide

Find Subarrays with Sum K - C++ Algorithm Guide

Understanding the Problem

Given an unsorted array of integers, you must find the total number of continuous subarrays where the elements add up to a specific integer k. This is a classic coding interview problem that tests your ability to optimize nested loops using auxiliary data structures.

Examples

Input: arr = [10, 2, -2, -20, 10], k = -10
Output: 3
Explanation: Subarrays: arr[0...3], arr[1...4], arr[3...4] have sum exactly equal to -10.
Input: arr = [9, 4, 20, 3, 10, 5], k = 33
Output: 2
Explanation: Subarrays: arr[0...2], arr[2...4] have sum exactly equal to 33.
Input: arr = [1, 3, 5], k = 0
Output: 0
Explanation: No subarray with 0 sum.

Constraints

  • 1 ≤ arr.size() ≤ 105
  • -103 ≤ arr[i] ≤ 103
  • -107 ≤ k ≤ 107

Optimized C++ Solution Using Prefix Sums

A naive approach would be to check every possible subarray using two nested loops. However, this yields a time complexity of O(N²), which is too slow for an array size of 105. Instead, we can optimize this to O(N) using a prefix sum and an unordered_map in C++.

As we iterate through the array, we maintain a currSum. If currSum - k exists in our map, it means there is a subarray ending at the current index which sums up to k. We then add the frequency of currSum - k to our result counter.

class Solution {
  public:
    int countSubarrays(vector<int> &arr, int k) {
        // unordered_map to store prefix sums frequencies
        unordered_map<int, int> prefixSums;
      
        int res = 0;
        int currSum = 0;

        for (int i = 0; i < arr.size(); i++) {
            // Add current element to sum so far.
            currSum += arr[i];

            // If currSum is equal to desired sum, then a new
            // subarray is found. So increase count of subarrays.
            if (currSum == k)
                res++;

            // Check if the difference exists in the prefixSums map.
            if (prefixSums.find(currSum - k) != prefixSums.end())
                res += prefixSums[currSum - k];

            // Add currSum to the set of prefix sums.
            prefixSums[currSum]++;
        }

        return res;
    }
};

Frequently Asked Questions

What is the optimal time complexity for finding subarrays with sum K?

The optimal time complexity is O(N) using a prefix sum array combined with an unordered map (hash table) to store frequencies of prefix sums. This allows us to look up the required difference in O(1) average time.

Why does the prefix sum approach work for finding a target sum?

The prefix sum approach works because the sum of any continuous subarray from index i to j can be expressed as the difference between the prefix sum up to j and the prefix sum up to i-1. By keeping track of the frequencies of all previous prefix sums, we can quickly count how many times a valid starting point occurred.

Mastering the prefix sum technique is essential for competitive programming and technical interviews. Practice similar problems to solidify your understanding of array manipulation and hash map optimizations!