[Medium] 525. Contiguous Array
Given a binary array nums, return the maximum length of a contiguous subarray with an equal number of 0 and 1.
Examples
Example 1:
Input: nums = [0,1]
Output: 2
Explanation: [0, 1] is the longest contiguous subarray with an equal number of 0 and 1.
Example 2:
Input: nums = [0,1,0]
Output: 2
Explanation: [0, 1] or [1, 0] is the longest contiguous subarray with an equal number of 0 and 1.
Constraints
1 <= nums.length <= 10^5nums[i]is either0or1.
Thinking Process
- Transformation:
0 → -1,1 → +1converts the problem to finding subarrays with sum 0
- Clarify if the array is sorted, has negatives, or allows duplicates.
- Prefix sums answer range queries; hash maps answer pair/count queries.
- In-place tricks use swap/write index instead of extra arrays.
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Prefix sum (this problem) | O(n) | O(n) | Range queries, subarray sum |
| Sort + scan | O(n log n) | O(1) | Intervals, meeting rooms |
| Kadane’s algorithm | O(n) | O(1) | Maximum subarray |
| Hash map counting | O(n) | O(n) | Frequency, two-sum variants |
Solution
Time Complexity: O(n)
Space Complexity: O(n)
Convert 0 to -1 and 1 to +1, then use prefix sum. When we see a prefix sum we’ve encountered before, the subarray between those two positions has equal 0s and 1s (net sum of 0).
class Solution:
def findMaxLength(self, nums):
first_index = {0: -1} # prefix sum 0 at virtual index -1
max_len = 0
count = 0
for i in range(len(nums)):
count += 1 if nums[i] == 1 else -1
if count in first_index:
max_len = max(max_len, i - first_index[count])
else:
first_index[count] = i
return max_len
Solution Explanation
Approach: Prefix sum (this problem)
Key idea: 1. Transformation: 0 → -1, 1 → +1 converts the problem to finding subarrays with sum 0
How the code works:
- Transformation:
0 → -1,1 → +1converts the problem to finding subarrays with sum 0- Clarify if the array is sorted, has negatives, or allows duplicates.
- Prefix sums answer range queries; hash maps answer pair/count queries.
- In-place tricks use swap/write index instead of extra arrays.
Walkthrough — input nums = [0,1], expected output 2:
[0, 1] is the longest contiguous subarray with an equal number of 0 and 1.
| Aspect | Complexity | |——–|————| | Time | O(n) - Single pass through array, hash map operations are O(1) | | Space | O(n) - Hash map stores at most n prefix sums |
Algorithm Breakdown
1. Initialize Hash Map
first_index: dict[int, int] = {}
first_index[0] = -1 # Base case
max_len, count = 0, 0
map[0] = -1: Represents prefix sum 0 before the array starts- This allows us to handle subarrays starting at index 0
count: Tracks the current prefix sum
2. Transform and Calculate Prefix Sum
count += 1 if nums[i] == 1 else -1
- Convert:
0→-1,1→+1 - Accumulate: Add to running count
3. Check for Repeated Prefix Sum
if count in first_index:
max_len = max(max_len, i - first_index[count])
else:
first_index[count] = i
- If prefix sum seen before: Subarray from
map[count] + 1toihas sum 0 - Length:
i - map[count](we don’t add 1 becausemap[count]is the index before the subarray starts)
4. Store First Occurrence
def find_max_length_bruteforce(nums: list[int]) -> int:
max_len = 0
for i in range(len(nums)):
zeros = ones = 0
for j in range(i, len(nums)):
if nums[j] == 0:
zeros += 1
else:
ones += 1
if zeros == ones:
max_len = max(max_len, j - i + 1)
return max_len
- Store only first occurrence: To maximize subarray length
- Later occurrences: Would give shorter subarrays
Why This Works
Mathematical Proof
For a subarray nums[i+1..j] to have equal 0s and 1s:
- Number of 1s = Number of 0s
- Sum of transformed values = 0
prefix[j] - prefix[i] = 0prefix[j] = prefix[i]
Therefore, if prefix[j] == prefix[i], the subarray nums[i+1..j] has equal 0s and 1s.
Example Explanation
nums = [0, 1, 0, 0, 1, 1, 0]
0 1 2 3 4 5 6
Transformed: [-1, +1, -1, -1, +1, +1, -1]
Prefix sums:
i=-1: prefix = 0 (base case)
i=0: prefix = -1
i=1: prefix = 0 ← Same as i=-1!
i=2: prefix = -1 ← Same as i=0!
i=3: prefix = -2
i=4: prefix = -1 ← Same as i=0!
i=5: prefix = 0 ← Same as i=-1!
i=6: prefix = -1 ← Same as i=0!
Subarray [0,5]: prefix[5] = 0 = prefix[-1]
Length = 5 - (-1) = 6 ✓
Subarray [1,5]: prefix[5] = 0 = prefix[1]
Length = 5 - 1 = 4 ✓
Complexity
| Aspect | Complexity | |——–|————| | Time | O(n) - Single pass through array, hash map operations are O(1) | | Space | O(n) - Hash map stores at most n prefix sums |
Common Mistakes
- All zeros or all ones:
[0,0,0]or[1,1,1]→0(no equal subarray) - Single element:
[0]or[1]→0 - Perfect balance:
[0,1]→2 -
Multiple valid subarrays:
[0,1,0,1,0,1]→6 - Missing base case: Forgetting
map[0] = -1causes issues with subarrays starting at index 0 - Wrong length calculation: Using
i - map[count] + 1instead ofi - map[count] - Updating map incorrectly: Updating map even when count exists (should only store first occurrence)
- Wrong transformation: Using
0 → 0and1 → 1instead of0 → -1and1 → +1
Detailed Example Walkthrough
Example: nums = [0,1,0,0,1,1,0]
Step 0: Initialize
map = {0: -1}
count = 0
maxLen = 0
Step 1: i=0, nums[0]=0
count = 0 + (-1) = -1
map.contains(-1)? No
map[-1] = 0
map = {0: -1, -1: 0}
maxLen = 0
Step 2: i=1, nums[1]=1
count = -1 + 1 = 0
map.contains(0)? Yes (at index -1)
maxLen = max(0, 1 - (-1)) = max(0, 2) = 2
map = {0: -1, -1: 0}
maxLen = 2
Step 3: i=2, nums[2]=0
count = 0 + (-1) = -1
map.contains(-1)? Yes (at index 0)
maxLen = max(2, 2 - 0) = max(2, 2) = 2
map = {0: -1, -1: 0}
maxLen = 2
Step 4: i=3, nums[3]=0
count = -1 + (-1) = -2
map.contains(-2)? No
map[-2] = 3
map = {0: -1, -1: 0, -2: 3}
maxLen = 2
Step 5: i=4, nums[4]=1
count = -2 + 1 = -1
map.contains(-1)? Yes (at index 0)
maxLen = max(2, 4 - 0) = max(2, 4) = 4
map = {0: -1, -1: 0, -2: 3}
maxLen = 4
Step 6: i=5, nums[5]=1
count = -1 + 1 = 0
map.contains(0)? Yes (at index -1)
maxLen = max(4, 5 - (-1)) = max(4, 6) = 6
map = {0: -1, -1: 0, -2: 3}
maxLen = 6
Step 7: i=6, nums[6]=0
count = 0 + (-1) = -1
map.contains(-1)? Yes (at index 0)
maxLen = max(6, 6 - 0) = max(6, 6) = 6
map = {0: -1, -1: 0, -2: 3}
maxLen = 6
Final result: 6
Why Store Only First Occurrence?
To maximize subarray length, we want the earliest starting position for each prefix sum.
Example:
prefix sums: [0, -1, 0, -1, 0, -1]
↑ ↑ ↑ ↑ ↑ ↑
i=-1 0 1 2 3 4
For prefix sum 0:
- First occurrence: i = -1
- Later occurrence: i = 1
Subarray ending at i=3:
- Using i=-1: length = 3 - (-1) = 4 ✓
- Using i=1: length = 3 - 1 = 2 ✗
Therefore, we should store only the first occurrence.
Related Problems
- 560. Subarray Sum Equals K - Find subarrays with sum k
- 974. Subarray Sums Divisible by K - Similar prefix sum pattern
- 325. Maximum Size Subarray Sum Equals k - Very similar
- 1124. Longest Well-Performing Interval - Similar technique
- 523. Continuous Subarray Sum - Check for multiples
Pattern Recognition
This problem demonstrates the Prefix Sum + Hash Map pattern:
- Transform problem into finding subarrays with target sum
- Use prefix sums to calculate subarray sums efficiently
- Hash map stores first occurrence of each prefix sum
- Look for repeated prefix sums to find valid subarrays
Key Insight:
- Subarray
nums[i+1..j]has sum 0 ifprefix[j] == prefix[i] - This extends to any target sum: subarray has sum k if
prefix[j] - prefix[i] == k
Applications:
- Finding subarrays with specific sum
- Finding subarrays with equal elements
- Finding subarrays with specific properties (balanced, etc.)
Optimization Tips
Early Exit (Not Applicable)
Since we need to check all positions, early exit isn’t possible.
Memory Optimization
For very large arrays, consider using array instead of hash map if prefix sum range is bounded.
Use contains() vs find()
def find_max_length_array(nums: list[int]) -> int:
n = len(nums)
offset = n
first_at = [-2] * (2 * n + 1) # -2 = not seen; prefix 0 stored at index offset
first_at[offset] = -1
max_len = count = 0
for i in range(n):
count += 1 if nums[i] == 1 else -1
idx = count + offset
if first_at[idx] != -2:
max_len = max(max_len, i - first_at[idx])
else:
first_at[idx] = i
return max_len
Both are O(1) average case, but contains() is more readable.
Code Quality Notes
- Readability: Clear variable names and logic
- Efficiency: Optimal O(n) time and space
- Correctness: Handles all edge cases properly
- Modern C++: Uses
contains()method (Python20)
This problem is a classic example of transforming a problem into a prefix sum problem. The key insight is converting the “equal 0s and 1s” constraint into “sum equals 0” after transformation.
Key Takeaways
- Transformation:
0 → -1,1 → +1converts the problem to finding subarrays with sum 0 - Prefix Sum: Track cumulative count from start
- Hash Map: Store first occurrence of each prefix sum for longest subarray
- Base Case:
map[0] = -1handles subarrays starting from index 0 - Repeated Prefix: If
prefix[i] == prefix[j], thensubarray[i+1..j]has sum 0
References
- LC 525: Contiguous Array on LeetCode
- LeetCode Discuss — LC 525: Contiguous Array
- LeetCode Editorial (may require premium)