【算法】求数组中累加和为定值的最长子数组

求累加和为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

  1. 初始的时候sum = 0 map{{0,-1}}
  2. 下标为0时,sum+=arr[1] , sum = 7 ,此时找sum-aim = 0的值出现在什么位置,map此时{{0,-1}},是-1位置,所以-1的下一个位置到这个位置的累加和一定是7, 所以【0,0】区间上肯定累加和是7。此时要把这条记录 {7,0} 增加到map中,表示累加到0位置,累加和为7。
  3. 下标为1时,sum += arr[1] , sum = 10,此时找sum - aim = 3出现在什么位置,发现map中没有累加和为3的。所以以arr[1]结尾的,不可能累加出aim的数组。 并将 {10,1}({sum,i})这条记录增加到map中
  4. 下标为2时,sum += arr[2} , sum = 12, 此时找sum-aim = 5出现在什么位置,发现map中没有累加和为5的。所以以arr[2]结尾的,不可能累加出aim的数组。并将{12,2} 这条数据加到map中
  5. 下标为3时,sum += arr[3], sum = 13,此时找sum - aim = 6 出现在什么位置,发现map中没有累加和为6的。所以以arr[3]结尾的,不可能累加出aim的数组。并将{13,3}这条数据加到map中
  6. 下标为4时,sum += arr[4], sum = 14, 此时找sum - aim = 7 出现在什么位置,发现map中有 {7,0} 这条数据,所以从0的下一个位置到4,也就是【1,4】能累加出7,记录一下长度。但是此时sum=14也是新出现的数字,将 {14,4}加这条数据入进map当中
  7. 下标为5时,sum += arr[5], sum = 21, 此时找sum - aim = 14 出现在什么位置,发现map中有 {14,4} ,所以从4的下一个位置也就是【5,5】来说肯定能累加出aim。此时sum = 21是新出现的, 将 {21,5}加入到map中
  8. 下标为6时,。。。
  9. 下标为7时,。。。
  10. 下标为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出现次数相等的最长子数组是多少?

算法思想: :类似。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值