文章目录
  1. 1. 问题
  2. 2. 分析

和前面那篇解决的问题是一样的,这里主要考虑第二种方法,将其转换为最长公共子序列的问题

问题


给定一个长度为N的数组a0,a1,a2…,an-1,找出一个最长的单调递增子序列
(注:递增的意思是对于任意的i<j,都满足ai<aj,此外子序列的意思是不要求连续,顺序不乱即可)。

例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8},则其最长的单调递增子序列为{5,6,7,8},长度为4。

分析


一种解法是转换为最长公共子序列问题,另外一种解法则是动态规划。这里考虑最长公共子序列的方法
1、将给定序列进行排序
2、对给定序列和排序序列求取最长公共子序列
3、由于有序序列保证了递增性,最终可以获得最长的递增子序列
这种方法有个问题:如果给定的序列存在相同的字符,求取的最长递增子序列包括相同的字符,需要根据需求进行去除。
最长公共子序列的问题参考 最长公共子序列
最终实现如下,完整代码下载在github-eesly

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
int mycmp(const void *a,const void *b)
{
	return (*((int*)a))-(*((int*)b));	//此处选择-号不要使用小于号,使用a-b对应小到大排序
}
int LCS(int a[],int lenA,int b[],int lenB)
{
	int **c = new int*[lenA+1];
	for(int i = 0; i <lenA+1; i++)
		c[i] = new int[lenB+1];
	//初始化c[i][0]和c[0][j]为0
	for(int i = 0; i<lenA; i++)
		c[i][0] = 0;
	for(int j = 0; j<lenB; j++)
		c[0][j] = 0;
	//两重循环,复杂度o(lenA*lenB)
	for(int i = 1; i<lenA+1; i++)
		for(int j = 1; j<lenB+1; j++)
		{
			//对于两个序列当前的值进行判断,如果相等则此时c[i][j]=c[i-1][j-1]+1;
			//含义:c[i][j]		表示a[0.....i]与b[0.....j]的最长公共子序列的长度
			//	    c[i-1][j-1]	表示a[0.....i-1]与b[0.....j-1]的最长公共子序列的长度
			if(a[i-1]==b[j-1])
				c[i][j] = c[i-1][j-1]+1;
			//如果不相等,则继承前面的最长的长度,离c[i][j]最近的分别为c[i][j-1]和c[i-1][j]
			else
				c[i][j] = c[i-1][j]>c[i][j-1]?c[i-1][j]:c[i][j-1];
		}

	//逆序输出最长递增子序列
	int i = lenA,j = lenB;
	int k = c[lenA][lenB]-1;
	int *LISq = new int[c[lenA][lenB]];
	while(i&&j)
	{
		if(a[i-1]==b[j-1]&&c[i][j] == c[i-1][j-1]+1)
		{
			LISq[k--] = a[i-1];
			i--;
			j--;
		}
		else if(a[i-1]!=b[j-1]&&c[i-1][j] > c[i][j-1])
			i--;
		else
			j--;			
	}
	printNum(LISq, c[lenA][lenB]);
	//资源回收
	int rs = c[lenA][lenB];
	for(int i = 0; i <lenA+1; i++)
		delete [] c[i];
	delete [] LISq;
	return rs;
}
int main()
{
	srand((unsigned)time(NULL));
	for(int i = 0; i < MAX_NUM; i++)
		a[i] = rand()%MAX_NUM;
	memcpy(b,a,MAX_NUM*sizeof(int));
	printNum(a,MAX_NUM);

	qsort(b,MAX_NUM,sizeof(int),mycmp);
	printNum(b,MAX_NUM);

	cout<<"最长递增子序列为:";
	int len = LCS(a,MAX_NUM,b,MAX_NUM);
	cout<<"最长递增子序列长度为:"<<len<<endl;

	system("pause");
}
文章目录
  1. 1. 问题
  2. 2. 分析

eesly_yuan

ee or cs, this is a question