最长递增子序列(longest increasing subsequence)

问题

给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)。例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8},则其最长的单调递增子序列为{5,6,7,8},长度为4.

int LIS(int nums[], int n, int result[]){//暴力法,时间O(n^2)
	int* lis = new int[n];
	int* pre = new int[n];
	int maxlen = 1, maxIndex = 0;
	lis[0] = 1;
	memset(pre, -1, n * sizeof(int));//此处不能用sizeof(pre),这是因为pre是指针,sizeof(pre)为4,并非数组的大小。
	for(int i = 1; i < n; i++){
		lis[i] = 1;//将int型的lis数组全初始化为1,不能用memset(lis, 1, n * sizeof(int)),这样赋值会使初值为00000001_00000001_00000001_00000001,为16843009。
					//memset是按字节赋值,因此只能全部赋值为0, 或者全部是f,即-1。
		for(int j = 0; j < i; j++)
			if(nums[i] > nums[j] && (lis[j] + 1) > lis[i]){
				lis[i] = lis[j] + 1;
				pre[i] = j;
			}
		if(lis[i] > maxlen){
			maxlen = lis[i];
			maxIndex =  i;
		}
	}
	int i = maxlen - 1;
	while(maxIndex != -1){
		result[i--] = nums[maxIndex];
		maxIndex = pre[maxIndex];
	}
	delete [] lis, delete [] pre;
	return maxlen;
}

int LIS2(int nums[], int n, int result[]){//采用二分查找,时间复杂度O(nlogn)
	int maxlen = 1, maxIndex = 0;
	int* maxNums = new int[n];//构建maxNums数组,其中maxNums[i]存储的是所有长度为i+1的最长递增子序列的最后一个元素的最小值
	int* index = new int[n];//index数组记录maxNums数组中对应元素在原nums数组中的秩
	int* pre = new int[n];//pre数组记录nums数组中每一元素的前驱的秩
	memset(pre, -1, n * sizeof(int));
	memset(index, 0, n * sizeof(int));
	maxNums[0] = nums[0];
	for(int i = 1; i < n; i++){//利用二分查找,在maxNums数组中查找nums[i]
		int lo = 0, hi = maxlen;
		while(lo < hi){
			int mi = (lo + hi) >> 1;
			if(maxNums[mi] < nums[i])
				lo = mi + 1;
			else 
				hi = mi;
		}//求出的lo为大于nums[i]的元素的最小秩。参考数据结构(C++第3版)P56
		if(lo == maxlen){//在maxNums中未找到nums[i],说明nums[i]大于maxNums中的最大值,则将此值插入maxNums中,maxlen长度加一。
			maxNums[maxlen] = nums[i];
			index[maxlen] = i;
			pre[i] = index[maxlen - 1];//当前元素的前驱的秩即为长度为maxlen - 1的最长递增子序列的最后一个元素的秩
			maxlen++;
			maxIndex = i;
		}
		else{
			maxNums[lo] = nums[i];//在maxNums中找到了nums[i],说明nums[i]小于原来位置的值,直接将原来位置的值替换
			index[lo] = i;
			pre[i] = (lo == 0) ? -1 : index[lo - 1];//当前元素的前驱的秩即为长度为lo - 1的最长递增子序列的最后一个元素的秩
		}
			
	}
	int j = maxlen - 1;
	while(maxIndex != -1){
		result[j--] = nums[maxIndex];
		maxIndex = pre[maxIndex];
	}
	delete [] maxNums, delete [] pre, delete [] index;
	return maxlen;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值