525. Contiguous Array
Problem Description
The problem provides an array nums
consisting of only binary digits (0s and 1s). The task is to find a contiguous subarray where the number of 0s and 1s are equal, and this subarray should be the longest of any such subarrays in the given array. The length of this subarray is what we need to return.
Contiguous means that the elements are consecutive, without any interruptions from elements that are not part of the subarray.
For example, if the input array is [0,1,0]
, the longest contiguous subarray with equal number of 0s and 1s would be [0, 1]
or [1, 0]
, and the length would be 2.
Intuition
The intuition behind the solution comes from the understanding that if we were to maintain a running difference between the number of 0s and 1s, a subarray with an equal number of 0s and 1s would correspond to a situation where the difference becomes zero. However, since we want to find the longest such subarray, we need a way to record the occurrences of the running difference.
Here's how we arrive at the solution:
- We use a variable to keep a running count of the number of 1s and 0s we've seen so far. Let's increment this count by 1 for every 1 we see and decrement it by 1 for every 0 we see in the array.
- We use a hashmap to keep track of the earliest index where each running count value has appeared.
- As we iterate through the array:
- We update the running count based on the current element.
- We check if the running count is already in the hashmap. If it's not, we add it to the hashmap with the current index.
- If the running count is already in the hashmap, it means we've found a subarray where the difference between the number of 0s and 1s is the same as some previous index, which implies that we have an equal number of 0s and 1s in between these two indexes.
- We calculate the length of this subarray by subtracting the previous index of this running count value from the current index and check if it's greater than the length of the previous longest subarray we've found. If it is, we update our answer.
- The maximum length found in this manner is the length of the longest contiguous subarray with equal numbers of 0s and 1s.
By following this approach, the algorithm elegantly handles the issue without having to compare every possible subarray, thereby reducing the complexity from O(n^2) to O(n).
Learn more about Prefix Sum patterns.
Solution Approach
The implementation of the solution utilizes a hashmap (dictionary in Python) and a single pass through the array, taking advantage of the prefix sum concept and storing indices where each sum first occurs. Here's a step-by-step breakdown of the code used:
-
Initialize a variable
s
to 0, which will be used to keep track of the running count (prefix sum) of the number of 1s and 0s seen so far in the array. When a1
is encountered in the array,s
is incremented by 1, and for a0
,s
is decremented by 1. -
Initialize another variable
ans
to 0, which will store the maximum length of the subarray found during the process. -
Create a hashmap
mp
with one initial key-value pair{0: -1}
, which signifies that before we start processing the array, the running count is 0 and its index is -1 (this helps handle cases where the subarray starts from index 0). -
Iterate through the array using a loop, and for each element at index
i
:- Update the running count
s
. If the valuev
is 1, increments
by 1. If not, decrements
by 1 (s += 1 if v == 1 else -1
). - Check if the running count
s
is already in the hashmapmp
.- If it is, compute the length of the subarray (
i - mp[s]
) which represents the distance from the first occurrence of this running count to the current index. Compare and update the answerans
to be the maximum length found so far (ans = max(ans, i - mp[s])
). - If it is not, add this running count
s
along with the current indexi
to the hashmap (mp[s] = i
), marking the first appearance of this running sum.
- If it is, compute the length of the subarray (
- Update the running count
-
After the loop concludes, the variable
ans
will hold the maximum length of the longest contiguous subarray with an equal number of 0s and 1s, which the function then returns.
In essence, the algorithm relies on the prefix sum pattern where changes in the running sum are monitored and recorded. When a running sum reoccurs, it indicates a potential subarray of interest. The hashmap acts as an efficient way to keep track of the indices where sums first occur, enabling the calculation of subarray lengths in constant time.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example using the given solution approach with the input array nums = [0, 1, 0, 1, 1, 0, 0]
.
The array is [0, 1, 0, 1, 1, 0, 0]
. We initialize s = 0
for the running count, ans = 0
for the maximum length of subarray, and a hashmap mp
with {0: -1}
.
Now, we iterate over the array and update our running count s
, the hashmap mp
, and our answer ans
.
- Step 1:
i = 0
,nums[i] = 0
.s = -1
(decremented from 0). This-1
is not inmp
, somp
is now{0: -1, -1: 0}
.ans
remains0
. - Step 2:
i = 1
,nums[i] = 1
.s = 0
(incrementing from -1).s
is inmp
at index-1
, soans = 1 - (-1) = 2
. - Step 3:
i = 2
,nums[i] = 0
.s = -1
(decremented from 0).s
is inmp
, so the length of this subarray is2 - 0 = 2
.ans = max(2, 2) = 2
. - Step 4:
i = 3
,nums[i] = 1
.s = 0
(incrementing from -1).s
is inmp
, so the length of this subarray is3 - (-1) = 4
.ans = max(2, 4) = 4
. - Step 5:
i = 4
,nums[i] = 1
.s = 1
(incremented from 0). This1
is not inmp
, somp
is now{0: -1, -1: 0, 1: 4}
.ans
remains4
. - Step 6:
i = 5
,nums[i] = 0
.s = 0
(decremented from 1).s
is inmp
, so the length of this subarray is5 - (-1) = 6
.ans = max(4, 6) = 6
. - Step 7:
i = 6
,nums[i] = 0
.s = -1
(decremented from 0).s
is inmp
, so the length of this subarray is6 - 0 = 6
.ans
remains6
as it's equal to the current maximum.
After going through the entire array, the longest contiguous subarray with an equal number of 0s and 1s is [1, 0, 1, 1, 0, 0]
starting from index 1 to index 6 and has a length of 6
. This is the final answer and is the value of ans
after iterating through the array.
Solution Implementation
1class Solution:
2 def findMaxLength(self, nums: List[int]) -> int:
3 # Initialize the current balance between 0s and 1s and the maximum length found
4 balance = max_length = 0
5 # Create a hash map to store the first occurrence of each balance
6 balance_map = {0: -1}
7
8 # Iterate over the elements in the array
9 for index, value in enumerate(nums):
10 # Update the balance (+1 for 1, -1 for 0)
11 balance += 1 if value == 1 else -1
12
13 # Check if the same balance has been seen before
14 if balance in balance_map:
15 # If we have seen this balance before, calculate the length of the subarray
16 # between the previous index and the current index
17 max_length = max(max_length, index - balance_map[balance])
18 else:
19 # If this is the first time we've seen this balance,
20 # store the index for this balance in the hash map
21 balance_map[balance] = index
22
23 # Return the maximum length of the subarray with equal number of 0s and 1s
24 return max_length
25
1class Solution {
2
3 // Function to find the maximum length of a contiguous subarray with equal number of 0s and 1s.
4 public int findMaxLength(int[] nums) {
5 // Create a hash map to store the sum so far (key) and its index (value).
6 Map<Integer, Integer> sumToIndexMap = new HashMap<>();
7
8 // Initialize the sum of elements to 0 and the answer to the max length to 0.
9 sumToIndexMap.put(0, -1); // Sum of 0 is considered to appear before the array starts.
10 int sum = 0, maxLength = 0;
11
12 // Iterate through the array.
13 for (int i = 0; i < nums.length; i++) {
14 // Update sum: +1 for '1', -1 for '0'. This helps in finding equal numbers of 1s and 0s.
15 sum += nums[i] == 1 ? 1 : -1;
16
17 // If the sum has been seen before, it means the subarray between the two indices has
18 // equal number of 0s and 1s.
19 if (sumToIndexMap.containsKey(sum)) {
20 // Update maxLength with the larger value between current maxLength and the distance
21 // between current index and the first index where this sum appeared.
22 maxLength = Math.max(maxLength, i - sumToIndexMap.get(sum));
23 } else {
24 // If sum is not found in the map, add it with its index.
25 sumToIndexMap.put(sum, i);
26 }
27 }
28
29 // Return the found maximum length.
30 return maxLength;
31 }
32}
33
1#include <vector>
2#include <unordered_map>
3using namespace std;
4
5class Solution {
6public:
7 // Function to find the maximum length of a contiguous subarray with an equal number of 0 and 1.
8 int findMaxLength(vector<int>& nums) {
9 unordered_map<int, int> prefixSumToIndex; // Map to store prefix sum to index mapping.
10 int currentSum = 0; // Current prefix sum.
11 int maxLength = 0; // Maximum length of the subarray found so far.
12 prefixSumToIndex[0] = -1; // Initialize with the base case prefix sum before any element is processed.
13
14 // Iterate through the array.
15 for (int i = 0; i < nums.size(); ++i) {
16 // Update the current sum: increment by 1 for a '1', decrement by 1 for a '0'
17 currentSum += nums[i] == 1 ? 1 : -1;
18
19 // Check if the current sum has been seen before.
20 if (prefixSumToIndex.count(currentSum)) {
21 // If yes, calculate the length of the subarray and update the maximum length.
22 maxLength = max(maxLength, i - prefixSumToIndex[currentSum]);
23 } else {
24 // If not, add the current sum and index to the map.
25 prefixSumToIndex[currentSum] = i;
26 }
27 }
28 return maxLength; // Return the maximum length found.
29 }
30};
31
1/**
2 * Finds the maximum length of a contiguous subarray with an equal number of 0 and 1.
3 * @param {number[]} nums - The input array containing 0s and 1s.
4 * @return {number} - The maximum length of a contiguous subarray with equal number of 0s and 1s.
5 */
6function findMaxLength(nums: number[]): number {
7 // Create a map to store the sum at each index. The map will help us find when we've seen a sum before.
8 const sumIndexMap = new Map<number, number>();
9 // Initialize sum for index -1 (before the start of the array) to 0.
10 sumIndexMap.set(0, -1);
11 let sum = 0; // This will hold our cumulative sum.
12 let maxLength = 0; // This will store the maximum length we find.
13
14 for (let i = 0; i < nums.length; ++i) {
15 // Update sum: decrement for 0 and increment for 1.
16 sum += nums[i] == 0 ? -1 : 1;
17
18 // If the sum has been seen before, we have found a subarray with equal number of 0s and 1s.
19 if (sumIndexMap.has(sum)) {
20 // The length is the current index - the previous index where we've seen the same sum.
21 maxLength = Math.max(maxLength, i - sumIndexMap.get(sum)!);
22 } else {
23 // If the sum hasn't been seen before, set the current index as the value for this sum.
24 sumIndexMap.set(sum, i);
25 }
26 }
27
28 // Return the maximum length found.
29 return maxLength;
30}
31
Time and Space Complexity
The time complexity of the code is O(n)
, as it iterates through the nums
list once, performing a constant amount of work for each element (checking and updating a dictionary, and updating a running sum and maximum length).
The space complexity of the code is O(n)
, in the worst case, where n
is the number of elements in the input list nums
. This is because the dictionary mp
can potentially store an entry for each unique sum encountered, which corresponds to each index in the list in the worst-case scenario.
Learn more about how to find time and space complexity quickly using problem constraints.
A heap is a ...?
Recommended Readings
Prefix Sum The prefix sum is an incredibly powerful and straightforward technique Its primary goal is to allow for constant time range sum queries on an array What is Prefix Sum The prefix sum of an array at index i is the sum of all numbers from index 0 to i By
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!