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

Example 1:

Input: [0,1]
Output: 2
Explanation: [0, 1] is the longest contiguous subarray with equal number of 0 and 1.

 

Example 2:

Input: [0,1,0]
Output: 2
Explanation: [0, 1] (or [1, 0]) is a longest contiguous subarray with equal number of 0 and 1.

 

Note: The length of the given binary array will not exceed 50,000.

题目大意:给定一个二值数组,返回含有相同个数的0和1的最长连续子数组的长度。

方法一:暴力法(超时)


C++代码

我们考虑所有的连续子数组,判断0和1个数是否相同,如果相同,则与当前已找到的符合条件的连续子数组的长度进行比较。

 1  int findMaxLength(vector<int>& nums) {
 2         int sum = 0;
 3         int maxsize = 0;
 4         for (int i = 0; i < nums.size(); ++i) {
 5             sum = 0;
 6             for (int j = i; j < nums.size(); ++j) {
 7                 //计算[i,j]的和,[i, j]的和=[i,j-1]的和+j,所以可以利用前面得到的结果
 8                 (nums[j] == 1) ? (sum += 1) : (sum -= 1);
 9                 if (sum == 0 && (maxsize < j - i + 1)) {
10                     maxsize = j - i + 1;
11                 }
12             }
13         }
14         return maxsize;
15     }

在这里,我们讨论索引[i,j]中1和0的个数是否相等时,避免直接统计1和0的个数,而是利用累加和,是1则加1,0则减1,累加和为0则代表1和0个数相同。

时间复杂度:$O(n^2)$

空间复杂度:$O(1)$


方法二:哈希表

假设S[i]表示数组索引为0到i的子数组各元素之和(遇到1则加1,遇到0则减1),如果S[i]=0,那么[0,i]组成的子数组是符合条件的;

假如S[i] !=0 且 S[i] = m,然而存在最小的$j \in [0,i)$使得S[j] = m,那么[j+1, i]是符合条件的连续子数组。因为S[i]=S[j],我们要根据累加和m,得到索引j,所以需要建立累加和映射到索引的哈希表。

累加和的取值范围为[-n, n](n为数组的长度,-n时表示数组全为-1, n时表示数组全为1),所以开辟一个2n+1的数组。

 1 int findMaxLength(vector<int>& nums) {
 2         int len = nums.size();
 3         vector<int> index(2 * len + 1, -2); //初始化为-2表示这些累加和尚未出现
 4         index[len] = -1; //一开始累加和为0,索引为-1
 5         int maxlen = 0, sum = 0;
 6         for (int i = 0; i < nums.size(); ++i) {
 7             sum += (nums[i] == 0) ? -1 : 1;
 8             if (index[sum + len] >= -1) { //如果当前累加和已经出现过,则比较大小并更新maxlen,这里就不用更新累加和对应的索引
 9                 maxlen = max(maxlen, i - index[sum + len]);
10             } else { //否则记录累加和对应的索引
11                 index[sum + len] = i;
12             }
13         }
14         return maxlen;
15     }

需要注意的是,累加和为m可能对应多个索引,因为要找最长的连续子数组,所以我们只能保存最小的索引。

时间复杂度:$O(n)$

空间复杂度:$O(n)$

或者利用STL map数据结构:

 1 int findMaxLength(vector<int>& nums) {
 2         int len = nums.size();
 3         unordered_map<int, int> hM;
 4         int maxlen = 0, sum = 0;
 5         for (int i = 0; i < nums.size(); ++i) {
 6             sum += (nums[i] == 0) ? -1 : 1;
 7             if (sum == 0)
 8                 maxlen = i + 1;
 9             if (hM.find(sum + len) != hM.end()) { 
10                 maxlen = max(maxlen, i - hM[sum + len]);
11             } else {
12                 hM[sum + len] = i;
13             }
14         }
15         return maxlen;
16     }

 


 

越努力,越幸运