Contiguous Array

Medium Hash Maps

Problem

Given a binary array nums, return the maximum length of a contiguous subarray with an equal number of 0 and 1.

  • 1 ≤ nums.length ≤ 10⁵
  • nums[i] is either 0 or 1

Example

Input: nums = [0,1,0]
Output: 2

The brute-force approach would check every possible subarray and count zeros and ones, resulting in O(n²) time complexity. Instead, the algorithm transforms the problem by treating 0 as -1 and 1 as +1, then uses a prefix sum to track the cumulative score. When the same score appears twice, it means the subarray between those indices has equal numbers of 0 and 1. For example, at index 0, score is -1; at index 1, score is 0 again, indicating the subarray from index 0 to 1 has equal zeros and ones. The algorithm records the earliest occurrence of each score in a hash map to quickly compute the maximum length.

Approach

Straightforward Solution

A brute-force approach would check all subarrays, counting zeros and ones each time, resulting in O(n²) time complexity, which is inefficient for large inputs.

Core Observation

The key insight is that equal numbers of 0 and 1 in a subarray correspond to a net zero sum when 0 is treated as -1 and 1 as +1. Thus, the problem reduces to finding the longest subarray with a cumulative sum of zero.

Path to Optimal

By converting 0s to -1s, the problem becomes finding the longest subarray with a prefix sum that repeats. Using a hash map to store the first occurrence of each prefix sum allows constant-time lookups to find the longest subarray with zero net sum. This reduces the time complexity to O(n).

Optimal Approach

Iterate through the array, updating a running score (+1 for 1, -1 for 0). For each score, check if it has been seen before in the hash map. If yes, update the maximum length with the distance between the current index and the first occurrence. If not, record the current index as the first occurrence. Return the maximum length found.

Time

O(n)

The algorithm makes a single pass through the array, performing constant-time operations for each element, including hash map lookups and updates.

Space

O(n)

In the worst case, the hash map stores a unique prefix sum for each index, requiring O(n) auxiliary space.

Pattern Spotlight

Hash Maps (Prefix Sum with First Occurrence Tracking)

When searching for the longest subarray with a certain cumulative property, transform the problem into prefix sums and use a hash map to record the earliest index of each prefix sum, enabling O(1) lookups to find subarrays with desired sums.

Solution

1class Solution:
2 def findMaxLength(self, nums: List[int]) -> int:
3
4 first_seen = {0: -1}
5 score = 0
6 best = 0
7
8 for i in range(len(nums)):
9
10 if nums[i] == 1:
11 score += 1
12 else:
13 score -= 1
14
15 if score in first_seen:
16 best = max(best, i - first_seen[score])
17 else:
18 first_seen[score] = i
19
20 return best

Step-by-Step Solution

1

Initialize Prefix Sum Map and Tracking Variables

4first_seen = {0: -1}
5score = 0
6best = 0

Objective

To set up a hash map to record the earliest index of each prefix sum and initialize variables to track the running score and best subarray length.

Key Insight

Initializing the hash map with score 0 mapped to index -1 handles the edge case where a valid subarray starts at index 0. The running score accumulates +1 for each 1 and -1 for each 0, enabling detection of balanced subarrays via repeated scores.

Interview Quick-Check

Core Logic

The hash map stores the earliest index where each prefix sum occurs, enabling O(1) lookups to find subarrays with zero net sum.

State & Boundaries

Mapping score 0 to index -1 allows subarrays starting at index 0 to be correctly measured.

Common Pitfalls & Bugs

Forgetting to initialize the hash map with {0: -1} causes incorrect length calculations for subarrays starting at the beginning.

2

Iterate Through Array and Update Running Score

8for i in range(len(nums)):
10 if nums[i] == 1:
11 score += 1
12 else:
13 score -= 1
15 if score in first_seen:
16 best = max(best, i - first_seen[score])
17 else:
18 first_seen[score] = i

Objective

To traverse the array, update the running score based on the current element, and use the hash map to find the longest balanced subarray.

Key Insight

By treating 0 as -1 and 1 as +1, the running score reflects the net difference between counts of 1s and 0s. When the same score repeats, the subarray between the first occurrence and current index has equal numbers of 0 and 1. Updating the best length at each repetition ensures the maximum length is tracked.

Interview Quick-Check

Core Logic

The running score increments by 1 for 1 and decrements by 1 for 0, transforming the problem into finding the longest subarray with zero net sum.

State & Boundaries

Check if the current score has been seen before; if yes, update the best length using the distance between current index and first occurrence.

Common Pitfalls & Bugs

Adding the current score to the map only if it hasn't been seen before preserves the earliest index, which is essential for maximizing subarray length.

3

Return the Maximum Length of Balanced Subarray

20return best

Objective

To return the length of the longest contiguous subarray with equal numbers of 0 and 1 found during iteration.

Key Insight

After processing all elements, the variable tracking the best length holds the maximum size of any balanced subarray. Returning this value completes the solution.

Interview Quick-Check

Core Logic

Returning the tracked maximum length ensures the correct answer is provided after a single pass.

Line Analysis

This solution has 3 Critical lines interviewers watch for.

Line 4 Critical
first_seen = {0: -1}

Initialize a hash map to record the earliest index of each prefix sum, starting with score 0 at index -1.

Mapping score 0 to index -1 is critical to correctly handle subarrays starting at index 0, enabling the algorithm to measure lengths from the start without special cases.

Line 15 Critical
if score in first_seen:

Check if the current running score has been seen before in the hash map.

Detecting repeated scores indicates a balanced subarray between the first occurrence and current index.

Line 16 Critical
best = max(best, i - first_seen[score])

Update the best length with the maximum of current best and the distance between current index and first occurrence of the score.

Calculating the subarray length from the earliest occurrence to current index ensures the longest balanced subarray is tracked.

Line 17 Core
else:

If the current score has not been seen before, record the current index as its first occurrence.

Storing only the earliest index preserves the longest possible subarray length for future matches.

Line 20 Core
return best

Return the maximum length of a balanced subarray found.

Returning the tracked best length completes the solution, providing the correct answer after a single pass.

Line 5 Core
score = 0

Initialize the running score to zero.

The running score tracks the net difference between counts of 1s and 0s, forming the basis for detecting balanced subarrays.

Line 10 Core
if nums[i] == 1:

Increment the running score by 1 if the current element is 1.

Treating 1 as +1 in the running score transforms the problem into tracking net balance between 1s and 0s.

Line 12 Core
else:

Decrement the running score by 1 if the current element is 0.

Treating 0 as -1 balances the score, enabling detection of equal counts via prefix sums.

Line 18 Core
first_seen[score] = i

Add the current score and index to the hash map.

This insertion enables future lookups to detect balanced subarrays starting after this index.

Line 6 Standard
best = 0

Initialize the variable to track the best (maximum) subarray length found so far.

This variable accumulates the maximum length of any balanced subarray encountered during iteration.

Line 11 Standard
score += 1

Increment the running score for 1s.

This line implements the increment operation for 1s, contributing to the net score.

Line 13 Standard
score -= 1

Decrement the running score for 0s.

This line implements the decrement operation for 0s, contributing to the net score.

Line 8 Standard
for i in range(len(nums)):

Start iterating through the array indices.

Iterating over each element allows the algorithm to update the running score and check for balanced subarrays in a single pass.

Test Your Understanding

Why does storing the first occurrence of each prefix sum enable finding the longest subarray with equal numbers of 0 and 1?

Because when the same prefix sum appears again at a later index, the subarray between these two indices has a net sum of zero, indicating equal numbers of 0 and 1. Storing the earliest occurrence ensures the longest possible subarray length is computed.

Related Problems

Hash Maps pattern

Don't just read it. Drill it.

Reconstruct Contiguous Array from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Contiguous Array drill

or drill a free problem