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

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

    一定要找到他俩的共同点,都是求所有的以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;
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值