fun subarraySum(nums: IntArray, k: Int): Int {
var count = 0
for (start in 0 until nums.size) {
for (end in start until nums.size) {
var sum = 0
for (k in star..end) {
sum += nums[k]
}
if (sum == k) count++
}
}
return count
}
// We can sum up while iterating the element, because sum of `start..end` is the sum of `start..end - 1` + `nums[end]`.
fun subarraySum(nums: IntArray, k: Int): Int {
var count = 0
for (start in 0 until nums.size) {
var sum = 0
for (end in start until nums.size) {
sum += nums[end]
if (sum == k) count++
}
}
return count
}- Time Complexity:
O(n^3)andO(n^2). - Space Complexity:
O(1).
We have prefix sum array pre[i], which is the sum of 0..i. And suppose we have another index j which i < j, then:
pre[j] = nums[0] + ... + ... + ... + ( ... + nums[j])
= nums[0] + nums[1] + ... + nums[i] + (nums[i + 1] + ... + nums[j])
= pre[i] + (nums[i + 1] + ... + nums[j])
// So we can transform the equation:
pre[j] = pre[i] + (nums[i + 1] + ... + nums[j])
pre[i] + k = pre[j]
// Transform to (the key formula)
pre[i] = pre[j] - kTo search pre[i] + k == pre[j], we can actually search if pre[j] - k exists (we had seen pre[i] before).
pre[j] - k = pre[i]indicates that sum ofA[i+1 : j] == k
Let's see an example:
k = 3
i = 0 1 2 3 4
nums = [2, 1, 3, -1, 1]
pre = [2, 3, 6, 5, 6]
i j
|--i
|------------j
|--k---|
pre[i] = 2 + 1
pre[j] = 2 + 1 + 3 + -1 + 1
= pre[i] + 3 + -1 + 1
pre[j] - pre[i] = 3 + -1 + 1
= kWe can apply the same approach in problem 1. Two Sum, we maintain a hash table with prefix sum as key and the count of the prefix sum as value. Then we can iterate j to sum up the prefixSum (that is pre[j]), then check if pre[j] - k (pre[i]) exists in the hash table. If it exists, then we found a subarray A[i+1 : j] that can sum up to k, and we add the count of the subarray from hash table to the result.
Let's see an example:
// Example 1
[1, 2, 3, 4], k = 5
i
prefixSum = 1
countMap.containsKey(1 - 5 = 4) = false
countMap[1] = 1 {0:1, 1:1} // Add the current prefixSum to the map
[1, 2, 3, 4], k = 5
i
prefixSum = 3
countMap.containsKey(3 - 5 = -2) = false
countMap[3] = 1 {0:1, 1:1, 3:1}
[1, 2, 3, 4], k = 5
^^^^
i
prefixSum = 6
countMap.containsKey(6 - 5 = 1) = true
count += countMap[1] = 1
countMap[6] = 1 {0:1, 1:1, 3:1, 6:1}
// Example 2
[1, 2, 3, 4], k = 7
^^^^
i
prefixSum = 10
countMap.containsKey(10 - 7 = 3) = true
count += countMap[3] = 1
countMap[10] = 1 {0:1, 1:1, 3:1, 6:1}fun subarraySum(nums: IntArray, k: Int): Int {
var count = 0
var prefixSum = 0
val countMap = HashMap<Int, Int>()
// We don't set value here
// countMap[0] = 1
for (i in 0 until nums.size) {
prefixSum += nums[i]
// We found the current `prefixSum == k`
if (prefixSum == k) count++
// We update the answer when we find the subarray
// with sum k by checking `prefixSum - k`
if (countMap.containsKey(prefixSum - k)) {
count += countMap[prefixSum - k]!!
}
// Increment the occurrence of current `prefixSum`
countMap[prefixSum] = (countMap[prefixSum] ?: 0) + 1
}
return count
}
// Or equivalent
fun subarraySum(nums: IntArray, k: Int): Int {
var count = 0
var prefixSum = 0
val countMap = HashMap<Int, Int>()
// The CATCH: This is for the case for `prefixSum` == k or `prefixSum - k == 0`
countMap[0] = 1
for (i in 0 until nums.size) {
prefixSum += nums[i]
if (countMap.containsKey(prefixSum - k)) {
count += countMap[prefixSum - k]!!
}
countMap[prefixSum] = (countMap[prefixSum] ?: 0) + 1
}
return count
}There are some critical points to pay attention to in our implementation and approach:
- We don't maintain the
prefixSumarray because we can iterate once to calculate theprefixSumand put it in the hash table. - For the case
prefixSum == k, we have to add the count ofprefixSum == kto the result, so we initialize theprefixSummap with0as key and1as value.
k = 2
nums = [1, 1, 2]
prefix = 1 2 4
* --> prefixSum - k = 0- If
prefixSum - kexists, we don't increment the count by 1 because it leads to WA, there might be multipleprefixSum - kexists, so we sum up the count by the number ofprefixSum - kexists. (Input[0, 0, 0], k =0)
input = 0, 0, 0
prefix= 0, 0, 0- This problem can't be solved by sliding window, because the input might be negative and the sum won't be always increasing when expanding (monotonic). There is no good way to decide when to shrink the window when the number is negative (
nums = [-1, -1, 1]andk = 0) or contains0(nums = [0, 1, 1, 0]andk = 2).
// Sliding Window, it doesn't work if nums contains negative number or 0, it only works if all numbers are positive.
fun subarraySum(nums: IntArray, k: Int): Int {
if (nums.size == 1 && nums[0] != k) return 0
var start = 0
var end = 0
var sum = 0
var count = 0
while (end < nums.size) {
sum += nums[end]
while (sum > k) {
sum -= nums[start]
start++
}
if (sum == k) {
count++
}
end++
}
return count
}Based on the characteristics of sliding window:
- If wider window is valid, then narrower window is also valid.
k = 3
nums = [1, 1, 1]
L R // valid
L R // invalid- If narrow window is invalid, then wider window is invalid as well.
k = 2
nums = [1, 1, 1, -1]
L R // invalid
L R // valid
L R // invalid- Time Complexity:
O(n). - Space Complexity:
O(n).
Initial
count = 0
countMap[0] = 1
// ----------------
// Example 1
[5, 8], k = 5
i
prefixSum = 5
countMap.containsKey(5 - 5) = countMap.containsKey(0) = true
count += countMap[0] = 1
countMap[5] = 1 {0:1, 5:1}
[5, 8], k = 5
i
prefixSum = 13
countMap.containsKey(13 - 5) = countMap.containsKey(8) = false+
countMap[13] = 1 {0:1, 5:1, 13:1}
// ----------------
// Example 2
[5, 8], k = 8
i
prefixSum = 5
countMap.containsKey(5 - 8) = countMap.containsKey(-3) = false
countMap[5] = 1 {0:1, 5:1}
[5, 8], k = 8
i
prefixSum = 13
countMap.containsKey(13 - 8) = countMap.containsKey(5) = true
countMap[13] = 1 {0:1, 5:1, 13:1}
// ----------------
// Example 3
[5, 8], k = 13
i
prefixSum = 13
countMap.containsKey(13 - 8) = countMap.containsKey(5) = true
countMap[13] = 1 {0:1, 5:1, 13:1}Input: nums = [1, 1, 1], k = 2
Output: 2
Input: nums = [1, 2, 3], k = 3
Output: 2
- All elements are
0:
Input: nums = [0, 0, 0], k = 0
Output: 6
- Positive + Negative + Zero:
Input: nums = [0, 1, -1, 0], k = 0
Output: 5
Input: nums = [1, -1, 0, 1, -1], k = 0
Output: 7
Input: nums = [1, -1, 1, -1, 1], k = 0
- All elements are equals to
k:
Input: nums = [2, 2, 2], k = 2
Output: 3