Given an array of integers nums
and an integer k
, return the total number of subarrays whose sum equals to k
.
A subarray is a contiguous non-empty sequence of elements within an array.
For example:
nums = [1, 1, 1], k = 2
. The expected output is 2 because the subarrays [1, 1]
and [1, 1]
both sum to 2.nums = [1, 2, 3], k = 3
. The expected output is 2 because the subarrays [1, 2]
and [3]
both sum to 3.Could you provide an efficient algorithm to solve this problem, considering the constraints:
1 <= nums.length <= 2 * 10^4
-1000 <= nums[i] <= 1000
-10^7 <= k <= 10^7
Explain the time and space complexity of your proposed solution. Also, discuss any potential edge cases and how your algorithm handles them.
A naive approach to solve this problem is to iterate through all possible subarrays and check if their sum equals k
. This involves two nested loops.
Algorithm:
i
.i
, iterate through the array from i
to the end using index j
.i
to j
.k
, increment the count.Code (Python):
def subarray_sum_brute_force(nums, k):
count = 0
for i in range(len(nums)):
for j in range(i, len(nums)):
current_sum = 0
for l in range(i, j + 1):
current_sum += nums[l]
if current_sum == k:
count += 1
return count
Time Complexity: O(n^3), due to the three nested loops.
Space Complexity: O(1), as it uses constant extra space.
An optimal approach involves using a hash map to store prefix sums and their frequencies. This reduces the time complexity significantly.
Algorithm:
prefix_sums
to store prefix sums and their counts. Initialize prefix_sums[0] = 1
to handle cases where a subarray starting from the beginning sums to k
.current_sum = 0
and count = 0
.nums
.current_sum
by adding the current element.current_sum - k
exists in prefix_sums
. If it does, it means there's a subarray ending at the current index with a sum of k
. Increment count
by the frequency of current_sum - k
in prefix_sums
.current_sum
in prefix_sums
.count
.Code (Python):
def subarray_sum_optimal(nums, k):
prefix_sums = {0: 1}
current_sum = 0
count = 0
for num in nums:
current_sum += num
if current_sum - k in prefix_sums:
count += prefix_sums[current_sum - k]
if current_sum in prefix_sums:
prefix_sums[current_sum] += 1
else:
prefix_sums[current_sum] = 1
return count
Time Complexity: O(n), as it iterates through the array once.
Space Complexity: O(n), in the worst case, the hash map prefix_sums
can store n
different prefix sums.
nums = [1, 2, 3, -3, 2, 1], k = 3
Using the optimal solution:
prefix_sums = {0: 1}, current_sum = 0, count = 0
num = 1, current_sum = 1
. prefix_sums = {0: 1, 1: 1}
num = 2, current_sum = 3
. current_sum - k = 0
. count = 1
. prefix_sums = {0: 1, 1: 1, 3: 1}
num = 3, current_sum = 6
. prefix_sums = {0: 1, 1: 1, 3: 1, 6: 1}
num = -3, current_sum = 3
. current_sum - k = 0
. count = 2
. prefix_sums = {0: 1, 1: 1, 3: 2, 6: 1}
num = 2, current_sum = 5
. prefix_sums = {0: 1, 1: 1, 3: 2, 6: 1, 5: 1}
num = 1, current_sum = 6
. current_sum - k = 3
. count = 2 + 2 = 4
. prefix_sums = {0: 1, 1: 1, 3: 2, 6: 2, 5: 1}
Result: 4