Given an array of integers nums and an integer k, return the total number of subarrays whose sum
equals to k.
Example 1:
Input: nums = [1, -1, 1, -1, 2, 3, 3, 4, 1, 5, 2], k = 8
Output: 5
Explanation: [1, -1, 1, -1, 2, 3, 3], [1,-1, 2, 3, 3], [2, 3, 3], [3, 4, 1] and [1, 5, 2]
are all possible subarrays whose sum = 8.
Playground: Leetcode 560
Naive Approach - Nested Loops
Iterate over all possible subarrays while maintaining a running sum for each subarray. Whenever the
sum becomes equal to k, increment the count of eligible subarrays.
Algorithm
1. Initialize a variable: "count" to track the number of eligible subarrays.
2. Iterate over each index in "nums", treating it as the starting index of the current subarray.
3. Initialize a variable: "currentSubarraySum = 0" to store the cumulative sum of the current subarray.
4. Starting from the current index, expand the subarray one element at a time.
5. Add the current element to "currentSubarraySum".
6. If "currentSubarraySum" equals "k", increment "count" by 1.
7. Return "count".
Implementation
Time Complexity
Updating and comparing currentSubarraySum are constant-time operations, O(1).
Therefore, the time complexity depends on the total number of times these operations
are performed.
The outer loop iterates over all n indices. For each starting index i, the inner loop
traverses n - i elements.
Therefore, the total number of operations is:
(n - 0) + (n - 1) + (n - 2) + ... + + (n - (n-1))
= 1 + 2 + 3 + ... + n
= n(n + 1) / 2
Since n(n + 1) / 2 grows proportionally to n², the overall time complexity is O(n²).
Space Complexity
Since we are not using any additional data structures and only a few variables (count, currentSum), the
extra space used does not grow with the input size.
Therefore, the overall space complexity is O(1).
Key Optimizations
Although we maintain a running sum within one iteration of the outer loop, we discard
that information when the starting index changes. For every starting index, we restart
currentSubarraySum from 0 and traverse the remaining elements.
Let's walk through the key intuition behind reducing this redundant work:
- The sum of any subarray can be obtained by subtracting two prefix sums. For example, in
nums = [1, -1, 1, -1, 2, 3, 3, 4, 1, 5, 2], we have subarray[3, 4, 1]ending at index8whose sum can be obtained by subtractingprefixSum[5]fromprefixSum[8].

- There can be multiple subarrays ending at
iwhose sum equalsk. For example, innums = [1, -1, 1, -1, 2, 3, 3, 4, 1, 5, 2], the subarrays[1, -1, 1, -1, 2, 3, 3],[1,-1, 2, 3, 3], and[2, 3, 3]all end at index6and have a sum of8.

Suitable Approach - Prefix Sum
Instead of exploring every possible subarray, maintain a running prefix sum while
traversing the array. At each index, check whether currentPrefixSum - k has appeared before.
Each occurrence represents a subarray ending at the current index whose sum is k.
Algorithm
1. Initialize
a. A variable: "count" to track the number of eligible subarrays.
a. A variable: "currentPrefixSum" to track the cumulative sum observed so far.
b. A frequency map: "prefixSumFrequencyMap" to track the frequencies of prefix sums
observed so far.
2. Add "{0: 1}" to handle the edge case where a subarray starting at index "0" has a sum
equal to "k".
3. Iterate over each element in "nums".
4. Add the current element to "currentPrefixSum".
5. If "prefixSumFrequencyMap" contains "currentPrefixSum - k", increment the "count" by
the frequency of "currentPrefixSum - k".
6. Add or update the frequency of "currentPrefixSum" in "prefixSumFrequencyMap".
7. Return "count".
Implementation
Time Complexity
Each iteration performs only constant-time operations, such as updating the prefix sum and
performing HashMap lookups and updates. We traverse the array exactly once, so the loop runs
n times.
Therefore, the overall time complexity is O(n) on average.
Space Complexity
In the worst case, all prefix sums are unique. Since we store each prefix sum in the HashMap,
the map can contain up to n entries.
Therefore, the overall space complexity is O(n).