题目:
给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
示例 1:
输入: nums = [0,1]
输出: 2
说明: [0, 1] 是具有相同数量0和1的最长连续子数组。
示例 2:
输入: nums = [0,1,0]
输出: 2
说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。
思路:
第一个想法就是暴力法搜索,计算数组中所有子集和, 然后记录子集和的下标,一旦子集的长度是子集和两倍,而且子集和大于0,避免00的情况。我们就返回长度,最终比较出最大长度。注意到我们的子集和从尾巴开始往前面累加。这样只需要2重循环。时间复杂度最大0(n^3),但是还是超时了。
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int len=nums.size();
if(len<2)
return 0;
int maxlength=0;
//暴力法
for(int i=len-1; i>=1;i--){
int sum=nums[i];
for(int j=i-1;j>=0;j--){
sum+=nums[j];
if(2*sum==(i-j+1) && sum>0)
maxlength=max(maxlength,i-j+1);
}
}
return maxlength;
}
};
解决办法:前缀和+哈希表,和之前前缀和的题目很像,只是我们更换了下筛选条件。我们知道01数量一致,我们把数组中0变成负1,那么0 1数量一致的子集就变成和为0的子集。即,我们不断存入这个前缀和到哈希表,如果出现过这个和的值,什么意思,意味着中间某一段到当前sum和为0,那就返回之前存的坐标和当前坐标的差,就是长度! 注意到我们要求最大长度,所以同样的sum我们只记录一次,程序中就是如果没出现这个值就进入哈希表,出现过就计算长度就好了。这样出来的就是最大长度。然后考虑一个情况,就是当前值就是0 1相同,sum=0怎么办,一开始没进入这个,所以我们要提前设置map[0]=-1,我们下标从0开始,0–1=1,以此类推没毛病。而且其他的中间过程 3-1=2也是对的。
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int len=nums.size();
if(len<2)
return 0;
//这个题目有点像昨天的题目啊,如果自己0=-1,累加值=0,那sum1=sum2了
unordered_map<int,int>map;
int sum=0;
int maxlength=0;
map[0]=-1;
for(int i=0;i<len;i++){
//变成0变成-1;
if(nums[i]==0){
int ans=-1;
sum=sum+ans;
}
else{
sum=sum+nums[i];
}
if(map.count(sum))
maxlength=max(maxlength,i-map[sum]);
else
map[sum]=i;
}
return maxlength;
}
};