🧠
Prefix Sum with Hash Map to Track First Occurrence
💡 This approach introduces a key insight: transform the problem by replacing 0s with -1s and track prefix sums to find subarrays with sum zero, enabling O(n) time complexity.
Intuition
Replace 0 with -1, so equal number of 0s and 1s means prefix sum difference is zero. Use a hash map to store first occurrence of each prefix sum to quickly find longest subarray.
Algorithm
- Initialize a hash map with prefix sum 0 at index -1.
- Iterate through the array, replacing 0 with -1 and computing prefix sums.
- If prefix sum has been seen before, update max_length with distance between current and first occurrence indices.
- Otherwise, store the current prefix sum and index in the hash map.
💡 The key is recognizing that equal zeros and ones correspond to prefix sums repeating, which allows constant time lookups for subarray lengths.
def findMaxLength(nums):
prefix_sum = 0
max_length = 0
first_occurrence = {0: -1}
for i, num in enumerate(nums):
prefix_sum += -1 if num == 0 else 1
if prefix_sum in first_occurrence:
max_length = max(max_length, i - first_occurrence[prefix_sum])
else:
first_occurrence[prefix_sum] = i
return max_length
# Driver code
if __name__ == '__main__':
print(findMaxLength([0,1,0,1,1,1,0])) # Expected output: 4
Line Notes
prefix_sum = 0Initialize prefix_sum to track running sum of transformed array
first_occurrence = {0: -1}Store prefix sum 0 at index -1 to handle subarrays starting at index 0
prefix_sum += -1 if num == 0 else 1Transform 0 to -1 and add to prefix_sum to track balance
if prefix_sum in first_occurrenceCheck if prefix_sum seen before to find balanced subarray length
import java.util.*;
public class Solution {
public static int findMaxLength(int[] nums) {
Map<Integer, Integer> firstOccurrence = new HashMap<>();
firstOccurrence.put(0, -1);
int prefixSum = 0, maxLength = 0;
for (int i = 0; i < nums.length; i++) {
prefixSum += (nums[i] == 0) ? -1 : 1;
if (firstOccurrence.containsKey(prefixSum)) {
maxLength = Math.max(maxLength, i - firstOccurrence.get(prefixSum));
} else {
firstOccurrence.put(prefixSum, i);
}
}
return maxLength;
}
public static void main(String[] args) {
int[] nums = {0,1,0,1,1,1,0};
System.out.println(findMaxLength(nums)); // Expected output: 4
}
}
Line Notes
Map<Integer, Integer> firstOccurrence = new HashMap<>();Hash map to store first occurrence of each prefix sum
firstOccurrence.put(0, -1);Initialize prefix sum 0 at index -1 for subarrays starting at 0
prefixSum += (nums[i] == 0) ? -1 : 1;Transform 0 to -1 and update prefix sum
if (firstOccurrence.containsKey(prefixSum))Check if prefix sum seen before to update maxLength
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
int findMaxLength(vector<int>& nums) {
unordered_map<int, int> firstOccurrence;
firstOccurrence[0] = -1;
int prefixSum = 0, maxLength = 0;
for (int i = 0; i < nums.size(); i++) {
prefixSum += (nums[i] == 0) ? -1 : 1;
if (firstOccurrence.find(prefixSum) != firstOccurrence.end()) {
maxLength = max(maxLength, i - firstOccurrence[prefixSum]);
} else {
firstOccurrence[prefixSum] = i;
}
}
return maxLength;
}
int main() {
vector<int> nums = {0,1,0,1,1,1,0};
cout << findMaxLength(nums) << endl; // Expected output: 4
return 0;
}
Line Notes
unordered_map<int, int> firstOccurrence;Hash map to store first occurrence indices of prefix sums
firstOccurrence[0] = -1;Initialize prefix sum 0 at index -1 for subarrays starting at 0
prefixSum += (nums[i] == 0) ? -1 : 1;Transform 0 to -1 and update prefix sum
if (firstOccurrence.find(prefixSum) != firstOccurrence.end())Check if prefix sum seen before to update maxLength
function findMaxLength(nums) {
const firstOccurrence = new Map();
firstOccurrence.set(0, -1);
let prefixSum = 0, maxLength = 0;
for (let i = 0; i < nums.length; i++) {
prefixSum += (nums[i] === 0) ? -1 : 1;
if (firstOccurrence.has(prefixSum)) {
maxLength = Math.max(maxLength, i - firstOccurrence.get(prefixSum));
} else {
firstOccurrence.set(prefixSum, i);
}
}
return maxLength;
}
// Test
console.log(findMaxLength([0,1,0,1,1,1,0])); // Expected output: 4
Line Notes
const firstOccurrence = new Map();Map to store first occurrence indices of prefix sums
firstOccurrence.set(0, -1);Initialize prefix sum 0 at index -1 for subarrays starting at 0
prefixSum += (nums[i] === 0) ? -1 : 1;Transform 0 to -1 and update prefix sum
if (firstOccurrence.has(prefixSum))Check if prefix sum seen before to update maxLength
Single pass through array with O(1) hash map operations per element, total O(n). Hash map stores prefix sums, worst case O(n) space.
💡 For n=10^5, this means about 100,000 operations, which is efficient and practical.
Interview Verdict: Accepted and optimal for this problem
This approach is the standard optimal solution and expected in interviews after explaining brute force.