数组字符串问题----数组的最长递增子数组

10 篇文章 0 订阅
问题:求数组的最长递增子数组的长度。
eg: 输入数组{1,-1,2,-3,4,-5,6,-7},因为最长递增子数组为
1 2 4 6 ,所以返回4.


方法一:
显然如果能穷举所有的递增子数组(不相包含),就可以得到最长的是什么。
假设有一个递增子串的集合,遍历数组的过程中维护这个集合:
索引   元素       子串集合
0      1           1
1      -1          1;-1
2      2           1,2;-1,2
3      -3          1,2;-1,2;-3
4      4           1,2,4;-1,2,4;-3,4
5      -5          1,2,4;-1,2,4;-3,4;-5
6      6           1,2,4,6;-1,2,4,6;-3,4,6;-5,6
7      -7          1,2,4,6;-1,2,4,6;-3,4,6;-5,6;-7


输出4


但问题只要求最长递增子串的长度,不必求字串的内容,可以简化:
我们是这样构造子串的:
当我们读到第三个数2时,只要求出以2结尾的串的最大长度就可以了。这样其后如果是比2大的数字,可在他的长度上递
增,其后是比2小的数与这里的计算结果就不搭了。最后我们求出的是以各个位置的数字结尾的递增字串的对大长度。
其中最大值即为输出。


故得到解结构:
输入pin,第i个数子结尾时,字串的最大长度
longest[i]=max{1,longest[k]} 1<=k<i && pin[k]<pin[i]


故有时间复杂度为O(n^2)的算法1:

int longestA(int* pin,int length)
{
	int longest[length];
	longest[0]=1;
	int max=1;
	for(int i=1;i<length;i++)
	{
		longest[i]=1;
		for(int j=0;j<i;j++)
		{
			if(pin[j]<pin[i] && longest[j]+1>longest[i])
				longest[i]=longest[j]+1;
		}
		if(longest[i]>max)
			max=longest[i];
	}
	return max;
			
}

方法二:


考虑对其方法一优化,求longset[i]时,遍历了之前所有的longsest结果。我门需要找到的是以小于pin[i]结尾的,长度最大
长的字串。故可以记录这两个量的组合:子串长度---结尾数字,而相同的长度会有不同的尾数字,我门只在意最小的
那个是否<pin[i],小则可以得到更长的子串。故该组合应为:子串长度----结尾数字的最小值。我们将所有组合按
长度从小到大排列,长度最大且结尾数字<pin[i] 的。


算法2时间复杂度仍O(n^2)

int longestB(int* pin,int length)
{
	int minTail[length+1];
	minTail[1]=pin[0];
	int maxlengh=1;
	
	for(int i=1;i<length;i++)
	{
		int mylength=1;
		for(int j=maxlengh;j>=1;j--)
             {
				 if(pin[i]>minTail[j])
					 {
						 mylength=j+1;
						 break;
					 }
			 }
	    if(mylength>maxlengh)
		{
           minTail[mylength]=pin[i];
		   maxlengh=mylength;
		}
		else
		{
			if(pin[i]<minTail[mylength])
				minTail[mylength]=pin[i];
		}
	}
	return maxlengh;
}

方法三:
数组minTail[i]  ,表示长度为i的递增子串的最小尾数.
实际上存在如下关系:
如果i<j  那么minTail[i]<minTail[j]
证明:
  假设minTail[j]<=minTail[i],则长度j的串中长度为i的子串其尾数必然<minTail[i].这和数组minTail的定义矛盾。

所以可以用二分查找实现在minTail中的查找:
算法复杂读为O(nlongn)

//二分查找,找第一个比n小的。
int halfSearch(int* pin,int nstart,int nend,int n)
{
	int mid;
	int nlow=nstart;
	int nhigh=nend;
	while(nhigh>=nlow)                //只有当所有数都大于n时,条件不成立,返回1
	{
		mid=(nhigh+nlow)/2;
		if(pin[mid]<n && ( mid+1>nend||pin[mid+1]>=n))
			return mid;                    //只要有小于n的元素就从这里返回
		else
			if( pin[mid]>=n)
                  nhigh=mid-1;
			else
				nlow=mid+1;
	}
	return 0;
}


int longestC(int* pin,int length)
{
	int minTail[length+1];
	minTail[1]=pin[0];
	int maxlengh=1;
	
	for(int i=1;i<length;i++)
	{
		int mylength=halfSearch(minTail,1,maxlengh,pin[i])+1;
	    if(mylength>maxlengh)
		{
           minTail[mylength]=pin[i];
		   maxlengh=mylength;
		}
		else
		{
			if(pin[i]<minTail[mylength])
				minTail[mylength]=pin[i];
		}
	}
	return maxlengh;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值