NYOJ--第214题单调递增数列(二)

这个题如果单纯的按照以前的方法来解决的话肯定会超时,所以需要我们对代码进行优化。优化用到了二分法,把以前那种(n^2)变成了(nlogn)其实我也是第一次接触二分法,之前对二分法并不是特别熟悉,所以就去百度了一下基本的概念。我觉得二分法可以单独整理一下。呵呵,废话不多说了,下面是代码和证明(证明是看的别人的,我也不是很明白,不过再思考一下应该可以明白)

原题地址:点击打开链接

代码如下:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int a[100002],d[100002];
int erfen(int num,int len)//二分函数
{
	int left,right,mid;
	left=1;
	right=len;
	mid=(left+right)/2;
	while(left<=right)
	{
		if(d[mid]<num)
			left=mid+1;
		else if(d[mid]>num)
			right=mid-1;
		else
			return mid;
		mid=(left+right)/2;
	}return left;
	}
int main()
{
	int n,len,i,j;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		memset(d,0,sizeof(0));
		len=1;
		d[1]=a[0];
		a[0]=-1000000;
		for(i=1;i<n;i++)
		{
			j=erfen(a[i],len);
			d[j]=a[i];
			if(j>len)
				len=j;
		}printf("%d\n",len);
	}return 0;
}

现在来证明这个算法为什么是正确的。要使算法正确只须证如下命题:

命题1:每一次循环结束数组B中元素总是按递增顺序排列的。

证明:用数学归纳法,对循环次数i进行归纳。

  当i=0时,即程序还没进入循环时,命题显然成立。

i<k时命题成立,当i=k时,假设存在j1<j2,B[j1]>B[j2],因为第i次循环之前数组B是递增的,因此第i次循环时B[j1]B[j2]必有一个更新,假设B[j1]被更新为元素ai+1,由于ai+1=B[j1]> B[j2],按算法ai+1应更新B[j2]才对,因此产生矛盾;假设B[j2]被更新,设更新前的元素为s,更新后的元素为ai+1,则由算法可知第i次循环前有B[j2]s< ai+1< B[j1],这与归纳假设矛盾。命题得证。

命题2B[c]中存储的元素是当前所有最长递增子序列长度为c的序列中,最小的最末元素,即设当前循环次数为i,有B[c]={aj| f(k)=f(j)=ck,ji+1ajak}(f(i)为与第二种算法中的f(i)含义相同)

证明:程序中每次用元素ai更新B[c](c=f(i)),设B[c]原来的值为s,则必有ai<s,不然ai就能接在s的后面形成长度为c+1的最长递增子序列,而更新B[c+1]而不是B[c]了。所有B[c]中存放的总是当前长度为c的最长递增子序列中,最小的最末元素。

命题3:设第i次循环后得到的pp(i+1),那么p(i)为以元素ai为最末元素的最长递增子序列的长度。

证明:只须证p(i)等于第二种算法中的f(i)。显然一定有p(i)<f(i)。假设p(i)<f(i),那么有两种情况,第一种情况是由二分查找法找到的p(i)不是数组B中能让ai接在后面成为新的最长递增子序列的最大的元素,由命题1和二分查找的方法可知,这是不可能的;第二种情况是能让ai接在后面形成长于p(i)的最长递增子序列的元素不在数组B中,由命题2可知,这是不可能的,因为B[c]中存放的是最末元素最小的长度为c的最长递增子序列的最末元素,若ai能接在长度为L(L> p(i))的最长递增子序列后面,就应该能接在B[L]后面,那么就应该有p(i)=L,L> p(i)矛盾。因此一定有p(i)f(i),命题得证。

算法的循环次数为n,每次循环二分查找用时logn,所以算法的时间复杂度为O(nlogn)。这个算法在第二种算法的基础上得到了较好的改进


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值