LC325. Maximum Size Subarray Sum Equals k¶
Problem Description¶
LeetCode Problem 325: Given an integer array nums
and an integer k
, return the maximum length of a subarray that sums to k
. If there is not one, return 0
instead.
Clarification¶
- Find the maximum length of subarray with
sum == k
- If doesn't exist, return 0
- Include both positive and negative values
Assumption¶
- Sum of subarray won't cause integer overflow
Solution¶
The general idea is to
- detect subarrays with sum k
- find the length of the longest subarray with sum k
-
The straightforward solution is using brute force with two for-loops to find all possible subarrays, which has \(O(n^2)\) time complexity. A better approach is to use prefix sum and hash map to detect subarray with sum k
more efficiently, which will reduce time complexity to \(O(n)\) but will use \(O(n)\) space.
Approach - Prefix Sum + Hash Map¶
A better approach to solve this problem is to use prefix sum and hash map. The prefix sum is the cumulative sum. The original array nums = [1, 2, 2, 3]
can be converted to the prefix sum array prefix = [1, 3, 5, 8]
. The prefix sum has the following properties:
- prefix[j] - prefix[i]
represents the sum of the subarray from i+1
to j
, where prefix[i]
is the sum of all the elements from 0
to i
(inclusive).
- If prefixSum[i] == prefixSum[j]
, then the sum of subarray from i+1
to j
equals 0
With above mentioned property, we can
- Store previously seen prefix sums and their indices in a hash map, map<prefixSum, index>
- No need to create a prefix sum array. Instead, use an integer variable to keep track of the prefix sum
- If running into duplicates (due to negative numbers), only update the index in the hash map when it doesn't exist (i.e., maps.find(prefixSum) == map.end()
), which keep the index as far to the left as possible, since we want the longest subarray.
- Check if prefix[i] == k
, then the sum of the subarray from 0
to i
is k
- Check it directly using if statement
- Or initialize the hash map with a key (prefix sum) of 0
corresponding to a value of -1
(index)
- Check if prefix[i] - k
has already been seen. If so (e.g., prefix[i] - k = prefix[j]
), the sum of the subarray from i+1
to j
is k
- Find the length of subarray using the stored index and current index and update longest length
Note: it's better replace integer with vector<int>::size_type
for indexing.
class Solution {
public:
vector<int>::size_type maxSubArrayLen(vector<int>& nums, int k) {
typedef vector<int>::size_type vec_size;
unordered_map<long, vec_size> sumIndexMap;
long int sum = 0;
vec_size length = 0;
vec_size maxLength = 0;
for (vec_size i = 0; i < nums.size(); i++) {
sum += nums[i];
// Check if cumulative sum == k
if (sum == k) {
if (i + 1 > maxLength) {
maxLength = i + 1;
}
}
// If any subarry with summmation == sum - k, update maxlenght
if (sumIndexMap.find(sum - k) != sumIndexMap.end()) {
length = i - sumIndexMap[sum - k];
if (length > maxLength) {
maxLength = length;
}
}
// Add the first appeared sum to hashmap for computing max length later
if (sumIndexMap.find(sum) == sumIndexMap.end()) {
sumIndexMap[sum] = i;
}
}
return maxLength;
}
};
Complexity Analysis¶
- Time complexity: \(O(n)\)
We iterate the array with one pass. Inside the for-loop, each code block is \(O(1)\). All hash map operators are \(O(1)\). - Space complexity: \(O(n)\)
The hash map can potential hold as many key-value pairs as numbers in
nums
. An example of this when there are NO negative numbers in the array.