求累加和为aim的最长子数组
O(N*N)的算法,我想大家都应该很了如指掌,那我们就讲一种O(N)的算法,借助map巧妙地解决。(主要在思想上,代码其实很简洁)
后面有类似思想拓展题。
【算法思想】:
我们准备一个map来完成记录操作。 map的意义是从开始累加到i位置的和为sum的时候,此时数组的下标i。且sum必须是新出现的。
初始的时候,map[0] = -1。 不能存0,因为没有元素的时候累加和就是0。(看例子好理解)
比如数组arr为 【7 ,3,2,1,1,7,-6,-1,7】 aim = 7
- 初始的时候sum = 0 map{{0,-1}}
- 下标为0时,sum+=arr[1] , sum = 7 ,此时找sum-aim = 0的值出现在什么位置,map此时{{0,-1}},是-1位置,所以-1的下一个位置到这个位置的累加和一定是7, 所以【0,0】区间上肯定累加和是7。此时要把这条记录 {7,0} 增加到map中,表示累加到0位置,累加和为7。
- 下标为1时,sum += arr[1] , sum = 10,此时找sum - aim = 3出现在什么位置,发现map中没有累加和为3的。所以以arr[1]结尾的,不可能累加出aim的数组。 并将 {10,1}({sum,i})这条记录增加到map中
- 下标为2时,sum += arr[2} , sum = 12, 此时找sum-aim = 5出现在什么位置,发现map中没有累加和为5的。所以以arr[2]结尾的,不可能累加出aim的数组。并将{12,2} 这条数据加到map中
- 下标为3时,sum += arr[3], sum = 13,此时找sum - aim = 6 出现在什么位置,发现map中没有累加和为6的。所以以arr[3]结尾的,不可能累加出aim的数组。并将{13,3}这条数据加到map中
- 下标为4时,sum += arr[4], sum = 14, 此时找sum - aim = 7 出现在什么位置,发现map中有 {7,0} 这条数据,所以从0的下一个位置到4,也就是【1,4】能累加出7,记录一下长度。但是此时sum=14也是新出现的数字,将 {14,4}加这条数据入进map当中
- 下标为5时,sum += arr[5], sum = 21, 此时找sum - aim = 14 出现在什么位置,发现map中有 {14,4} ,所以从4的下一个位置也就是【5,5】来说肯定能累加出aim。此时sum = 21是新出现的, 将 {21,5}加入到map中
- 下标为6时,。。。
- 下标为7时,。。。
- 下标为8时 ,。。。
代码实现:
int maxLength(vector<int>& arr, int aim)
{
if(arr.empty())
{
return 0;
}
map<int,int> mymap;
mymap[0] = -1;
int len = 0;
int sum = 0;
for(int i = 0; i < arr.size(); i++)
{
sum += arr[i];
if(mymap.find(sum - aim) != mymap.end())
{
len = max(i - mymap[sum - aim] , len);
}
if(mymap.find(sum) == mymap.end())
{
mymap[sum] = i;
}
}
return len;
}
拓展题1:一堆数有奇数有偶数,求奇数和偶数个数相等的最长子数组?
算法思想:奇数变为-1,偶数变为1,求最大累加和为0的最长子数组
拓展题2:一个数组中有0,1,2,求1和2出现次数相等的最长子数组是多少?
算法思想: :类似。