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 }