您的位置:首页 > 其它

未排序数组中累加和小于给定值的最长子数组长度

2016-01-21 23:40 411 查看
本体和本博客里另外一个文章,累加和等于给定值的最长子数组,非常类似,但是上一个题目来说,为了节省时间,使用了哈希表,但是那个题目是,等于,所以哈希表里有,就直接拿,没有,就跳过了,但是本题目是要求,小于或者等于,没办法直接查找,难道要遍历哈希表吗,这样时间复杂度又上去了,所以这里给出了一个新的数组,用作辅助

一定要找到他俩的共同点,都是求所有的以a【i】为结尾的数组中,累加和小于给定值的最长子数组长度。

本题举例来说,{3,-2,-4,0,6}

如果我们要求这个数组,则首先建立sum数组,就是以a[0]开始,a[i]结尾的数组的和

sum数组为{3,1,-3,-3,3},元素sum[i]代表以arr[0]开头,arr【i】结尾的子数组的和

另外建立辅助数组help

help[i]表示已arr[0]开头,arr[i]结尾的数组中,曾经出现的最大累加和

help数组为{3,3,3,3,3}

我们可以分析如下

当累加到元素0的时候,sum为3,就是本元素,然后我们可以这样考虑,既然要寻找以arr【0】开头,arr【0】为结尾和小于等于k的最长子数组,是不是说,我们找到了以arr【0】开头,第一次和大于等于sum-k的子数组,它后面就是我们要求的呢?(为什么叫第一次,因为数组未必全是正数,有可能后面还会多次出现和大于等于sum-k这个情况),本处来说,我们就是寻找前面和大于等于3-(-2)=5这样的子数组

这时候,我们前面建立的help数组就开始发挥威力了,我们其实可以得知,help的意义在于表明累加到该处时,出现过的最大累加和,相当于维持一个max,所以这个数组是单调递增的,而既然是递增数组,我们就可以使用二分搜索,将时间复杂度将为log(n);

sum-(-2)=5,我们就开始找,好吧,help数组里没有5,代表不存在

累加到元素1的时候,sum为1,1-(-2)=3,我们开始寻找help数组中哪个位置的元素开始第一次大于等于3,明显是索引0,所以意思就是说,从arr[0]后面到arr【1】,这一段就是要求的,这一段长度为1

累加到元素2的时候,sum为-3,-3-(-2)=-1

这时候,我们要非常注意一个事情,这件事情很重要,算个特殊情况,如果我们此时得到的sum,本身就是小于k的,比如这里,sum是-3,k是-2,我们其实已经不用找了,这一段子序列本身就代表了。

所以本处则是这个特殊条件,长度为3

累加到元素3的时候,sum为-3,和上个情况类似,长度为4

累加到元素4 的时候,sum和为3,3-(-2)=5,在help数组中没有找到,代表不存在

代码如下:

#include <iostream>
#include <algorithm>
using namespace std;
#define  MAXSIZE 1010
int arr[]={3,-2,-4,0,6};
int help[MAXSIZE];
int k=-2;
int len=5;
//sum[i]代表以arr[0]为开头,arr[i]为结尾的子数组的和
//help[i]代表以arr[0]开头 arr[i]结尾的子数组中出现的最大累加和
int getLessestIndex(int num)
{
int ret=-1;
int mid;
int start=0,end=len-1;
while(start<=end)
{
mid=(start+end)/2;
if(help[mid]>=num)
{
ret=mid;
end=mid-1;
}
else
{
start=mid+1;
}
}
return ret;
}
int fun()
{
int sum=0;
int i,j;
int maxnum=0;
int ret=0;
int index;
//help数组初始化
for(i=0;i<len;i++)
{
sum+=arr[i];
maxnum=max(maxnum,sum);
help[i]=maxnum;
}
sum=0;
for(i=0;i<len;i++)
{
sum+=arr[i];
if(sum<=k)
{
ret=max(ret,i+1);
}
else
{
index=getLessestIndex(sum-k);
if(index!=-1)
{
ret=max(ret,i-index);
}
}
}
return ret;
}
int main()
{
//初始化help数组
cout<<fun()<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: